CertC++-PRE32¶
Do not use preprocessor directives in invocations of function-like macros
Required inputs: IR
The arguments to a macro must not include preprocessor directives, such as
#define,
#ifdef, and
#include. Doing so results in
undefined
behavior, according to the C Standard, 6.10.3, paragraph 11 [
ISO/IEC
9899:2011]:
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. If there are sequences of preprocessing tokens within the list of arguments that would otherwise act as preprocessing directives, the behavior is undefined.
See also undefined behavior 93.
This rule also applies to the use of preprocessor directives in arguments to
any function where it is unknown whether or not the function is implemented
using a macro. This includes all standard library functions, such as
memcpy(),
printf(), and
assert(), because any standard library function may be implemented
as a macro. (C11, 7.1.4, paragraph 1).
Noncompliant Code Example
In this noncompliant code example [
GCC Bugs], the programmer uses preprocessor directives to
specify platform-specific arguments to
memcpy(). However, if
memcpy() is implemented using a macro, the code results in
undefined behavior.
#include <string.h>
void func(const char *src) {
/* Validate the source string; calculate size */
char *dest;
/* malloc() destination string */
memcpy(dest, src,
#ifdef PLATFORM1
12
#else
24
#endif
);
/* ... */
}
Compliant Solution
In this compliant solution [
GCC Bugs], the appropriate call to
memcpy() is determined outside the function call:
#include <string.h>
void func(const char *src) {
/* Validate the source string; calculate size */
char *dest;
/* malloc() destination string */
#ifdef PLATFORM1
memcpy(dest, src, 12);
#else
memcpy(dest, src, 24);
#endif
/* ... */
}
Risk Assessment
Including preprocessor directives in macro arguments is undefined behavior.
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| PRE32-C | Low | Unlikely | Medium | P2 | L3 |
Bibliography
| [ GCC Bugs] | "Non-bugs" |
| [ ISO/IEC 9899:2011] | 6.10.3, "Macro Replacement" |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
pp_directive_as_macro_arg |
Macro invocation argument looks like preprocessing directive |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
directives¶
directives
Preprocessing directives to check for in macro arguments.Type: set[str]
Default:
{'#asm', '#define', '#elif', '#else', '#endasm', '#endif', '#endregion', '#error', '#ident', '#if', '#ifdef', '#ifndef', '#include', '#include_next', '#line', '#pragma', '#region', '#undef', '#warning'}