parts/6.51.Pre-processorDirectives-NMP.md

6.51 Pre-processor Directives [NMP]

6.51.1 Applicability to language

The vulnerability as described in ISO/IEC TR 24772-1:2019 clause 6.51 applies to C++.

The C++ pre-processor allows the use of macros that are text-replaced before compilation.

Function-like macros look similar to functions but have different semantics. Because the arguments are text-replaced, expressions passed to a function-like macro may be evaluated multiple times. This can result in unintended and undefined behaviour if the arguments have side effects or are pre-processor directives. Additionally, the arguments and body of function-like macros should be fully parenthesized to avoid unintended and undefined behaviour.

The following code example demonstrates undefined behaviour when a function-like macro is called with arguments that have side-effects (in this case, the increment operator) .

#define CUBE(X) ((X) \* (X) \* (X))
// ...
  int i = 2;
  int a = 81 / CUBE(++i);

The above example could expand to:

  int a = 81 / ((++i) * (++i) * (++i));

which has undefined behaviour so this macro expansion is difficult to predict.

Another mechanism of failure can occur when the arguments within the body of a function-like macro are not fully parenthesized. The following example shows the CUBE macro without parenthesized arguments.

#define CUBE(X) (X \* X \* X)
// ...
int a = CUBE(2 + 1);

This example expands to:

int a = (2 + 1 * 2 + 1 * 2 + 1)

which evaluates to 7 instead of the intended 27.

6.51.2 Avoidance mechanisms for language users

To avoid the vulnerability or mitigate its ill effects, C++ software developers can: