12.8 Syntax Taints
Syntax Taints in The Racket Guide introduces syntax taints.
The tamper status of a syntax object is either tainted, armed, or clean:
A tainted identifier is rejected by the macro expander for use as either a binding or expression. If a syntax object is tainted, then any syntax object in the result of (syntax-e stx) is tainted, and datum->syntax with stx as its first argument produces a tainted syntax object.
Other derived operations, such as pattern matching in syntax-case, also taint syntax objects when extracting them from a tainted syntax object.
An armed syntax object has a set of dye packs, which creates taints if the armed syntax object is used without first disarming the dye packs. In particular, if a syntax object is armed, syntax-e, datum->syntax, quote-syntax, and derived operations effectively treat the syntax object as tainted. The macro expander, in contrast, disarms dye packs before pulling apart syntax objects.
Each dye pack, which is added to a syntax object with the syntax-arm function, is keyed by an inspector. A dye pack can be disarmed using syntax-disarm with an inspector that is the same as or a superior of the dye pack’s inspector.
A clean syntax object has no immediate taints or dye packs, although it may contain syntax objects that are tainted or armed.
Taints cannot be removed, and attempting to arm a syntax object that is already tainted has no effect on the resulting syntax object.
The macro expander disarms any syntax object that it encounters in an expression position or as a module body. A syntax object is therefore disarmed when it is provided to a syntax transformer. The transformer’s result, however, is rearmed by copying to it any dye packs that were originally attached to the transformer’s input. The rearming process obeys the following rules:
If the result has a 'taint-mode property (see Syntax Object Properties) that is 'opaque, then dye packs are attached to the immediate syntax object.
If the result has a 'taint-mode property that is 'none, then no dye pack is attached to the syntax object. The 'none mode is rarely appropriate.
If the result has a 'taint-mode property that is 'transparent, then the dye packs are propagated recursively to syntax object that corresponds to elements of the syntax object’s datum as a list (or, more precisely, to the cars of the datum as reached by any number of cdrs), and the immediate syntax object loses its lexical context; If the immediate syntax object is already armed, then recursive propagation taints the elements. Recursive propagation uses syntax properties and shapes, as for the immediate rearming.
If the result has a 'taint-mode property that is 'transparent-binding, then dye packs are attached in a way similar to 'transparent, but further treating the syntax object corresponding to the second list element as having a 'transparent value for the 'taint-mode property if it does not already have a 'taint-mode property value.
If the result has no 'taint-mode property value, but its datum is a pair, and if the syntax object corresponding to the car of the pair is an identifier bound to begin, module, or #%plain-module-begin, then dye packs are propagated as if the syntax object had the 'transparent property value.
If the result has no 'taint-mode property value, but its datum is a pair, and if the syntax object corresponding to the car of the pair is an identifier bound to define-values or define-syntaxes, then dye packs are propagated as if the syntax object had the 'transparent-binding property value.
For backward compatibility, a 'certify-mode property is treated the same as a 'taint-mode property if the former is not attached. To avoid accidental transfer of a 'taint-mode or 'certify-mode property value, the expander always removes any 'taint-mode and 'certify-mode property on a syntax object that is passed to a syntax transformer.
(syntax-tainted? stx) → boolean?
stx : syntax?
(syntax-arm stx [inspector use-mode?]) → syntax?
stx : syntax? inspector : (or/c inspector? #f) = #f use-mode? : any/c = #f
A #f value for inspector is equivalent to an inspector that depends on the current dynamic context:
when applying a syntax transformer is being applied, the declaration-time code inspector of the module in which a syntax transformer was bound;
when a module is being visited, the module’s declaration-time code inspector;
If use-mode? is #f, then if stx is tainted or already armed with the key inspector, the result is stx.
If use-mode? is a true value, then a dye pack is not necessarily added directly to stx. Instead, the dye pack is pushed to interior syntax objects in the same way that the expander pushes armings into a syntax transformer’s results when rearming (based on a 'taint-mode syntax property or identifier bindings); see the expander’s rearming rules for more information. To the degree that pushing dye packs into a syntax object must destructure stx, existing taints or dye packs can lead to tainted results rather than armed results.
(syntax-protect stx) → syntax?
stx : syntax?
(syntax-disarm stx inspector) → syntax?
stx : syntax? inspector : (or/c inspector? #f)
(syntax-rearm stx from-stx [use-mode?]) → syntax?
stx : syntax? from-stx : syntax? use-mode? : any/c = #f
If use-mode? is a true value, stx is not necessarily tainted or armed directly. Instead, taints or dye packs are pushed to interior syntax objects in the same way as for syntax-arm or rearming by the expander.
(syntax-taint stx) → syntax?
stx : syntax?