The arguments to a macro should not include preprocessor directives such as #define
, #ifdef
, and #include
. Doing so is undefined behavior according to section 6.10.3.1, paragraph 11 of the C99 standard [[ISO/IEC 9899:1999]] (see also undefined behavior 87 of Annex J):
<blockquote><p>The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro. The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments. <strong>If there are sequences of preprocessing tokens within the list of arguments that would otherwise act as preprocessing directives, the behavior is undefined.</strong></p></blockquote>The scope of this rule includes using preprocessor directives in arguments to a function where it is unknown whether or not the function is implemented using a macro. For example, standard library functions such as memcpy()
, printf()
, and assert()
may be implemented as macros.
Noncompliant Code Example
In this noncompliant code example [GCC Bugs], the author uses preprocessor directives to specify platform-specific arguments to memcpy()
. However, if memcpy()
is implemented using a macro, the code results in undefined behavior.
memcpy(dest, src, #ifdef PLATFORM1 12 #else 24 #endif );
Compliant Code Example
In this compliant solution [GCC Bugs], the appropriate call to memcpy()
is determined outside the function call.
#ifdef PLATFORM1 memcpy(dest, src, 12); #else memcpy(dest, src, 24); #endif
Risk Assessment
Improper use of macros may result in undefined behavior.
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
PRE32-C |
low |
unlikely |
medium |
P2 |
L3 |
References
[GCC Bugs] "Non-bugs"
[[ISO/IEC 9899:1999]] Section 6.10.3.1, "Argument substitution," paragraph 11
PRE31-C. Never invoke an unsafe macro with arguments containing assignment, increment, decrement, volatile access, or function call 01. Preprocessor (PRE) 02. Declarations and Initialization (DCL)