16.2.7 Tainted Syntax

► |  | The Racket Guide

1 | Welcome to Racket
2 | Racket Essentials
3 | Built-In Datatypes
4 | Expressions and Definitions
5 | Programmer-Defined Datatypes
6 | Modules
7 | Contracts
8 | Input and Output
9 | Regular Expressions
10 | Exceptions and Control
11 | Iterations and Comprehensions
12 | Pattern Matching
13 | Classes and Objects
14 | Units
15 | Reflection and Dynamic Evaluation
16 | Macros
17 | Creating Languages
18 | Concurrency and Synchronization
19 | Performance
20 | Parallelism
21 | Running and Creating Executables
22 | More Libraries
23 | Dialects of Racket and Scheme
24 | Command-Line Tools and Your Editor of Choice
| Bibliography
| Index

► | 16 | Macros

16.1 | Pattern-Based Macros
16.2 | General Macro Transformers
16.3 | Module Instantiations and Visits

▼ | 16.2 | General Macro Transformers

16.2.1 | Syntax Objects
16.2.2 | Macro Transformer Procedures
16.2.3 | Mixing Patterns and Expressions: syntax-case
16.2.4 | with-syntax and generate-temporaries
16.2.5 | Compile and Run-Time Phases
16.2.6 | General Phase Levels
16.2.7 | Tainted Syntax

Racket
top contents ← prev up next →

#### 16.2.7 Tainted Syntax🔗ℹ

Modules often contain definitions that are meant only for use within the same module and not exported with provide. Still, a use of a macro defined in the module can expand into a reference of an unexported identifier. In general, such an identifier must not be extracted from the expanded expression and used in a different context, because using the identifier in a different context may break invariants of the macro’s module.

For example, the following module exports a macro go that expands to a use of unchecked-go:

> > "m.rkt"

> > > #lang racket
> > > (provide go)
> > > (define (unchecked-go n x)
> > > ; to avoid disaster, n must be a number
> > > (+ n 17))
> > > (define-syntax (go stx)
> > > (syntax-case stx ()
> > > [(_ x)
> > > #'(unchecked-go 8 x)]))

If the reference to unchecked-go is extracted from the expansion of (go 'a), then it might be inserted into a new expression, (unchecked-go #f 'a), leading to disaster. The datum->syntax procedure can be used similarly to construct references to an unexported identifier, even when no macro expansion includes a reference to the identifier.

Ultimately, protection of a module’s private bindings depends on changing the current code inspector by setting the current-code-inspector parameter. See also Code Inspectors for Trusted and Untrusted Code. That’s because a code inspector controls access to a module’s internal state through functions like module->namespace. The current code inspector also gates access to the protected exports of unsafe modules like racket/unsafe/ops.

Since the result of macro expansion can be abused to gain access to protected bindings, macro functions like local-expand are also protected: references to local-expand and similar are allowed only within modules that are declared while the original code inspector is the current code inspector. Functions like expand, which are not used to implement macros but are used to inspect the result of macro expansion, are protected in a different way: the expansion result is tainted so that it cannot be compiled or expanded again. More precisely, functions like expand accept an optional inspector argument that determines whether the result is tainted, but the default value of the argument is (current-code-inspector).

> > > In previous versions of Racket, a macro was responsible for protecting expansion using syntax-protect. The use of syntax-protect is no longer required or recommended.

top contents ← prev up next →