The C Standard, 7.1.4 paragraph 1, [ISO/IEC 9899:2011] states
Any function declared in a header may be additionally implemented as a function-like macro defined in the header, so if a library function is declared explicitly when its header is included, one of the techniques shown below can be used to ensure the declaration is not affected by such a macro. Any macro definition of a function can be suppressed locally by enclosing the name of the function in parentheses, because the name is then not followed by the left parenthesis that indicates expansion of a macro function name. For the same syntactic reason, it is permitted to take the address of a library function even if it is also defined as a macro.185
185) This means that an implementation shall provide an actual function for each library function, even if it also provides a macro for that function.
However, the C Standard enumerates specific exceptions in which the behavior of accessing an object or function expanded to be a standard library macro definition is undefined. The macros are assert
, errno
, math_errhandling
, setjmp
, va_arg
, va_copy
, va_end
, and va_start
. These cases are described by undefined behaviors 110, 114, 122, 124, and 138. Programmers must not suppress these macros to access the underlying object or function.
Noncompliant Code Example (assert
)
In this noncompliant code example, the standard assert()
macro is suppressed in an attempt to pass it as a function pointer to the execute_handler()
function. Attempting to suppress the assert()
macro is undefined behavior.
#include <assert.h> typedef void (*handler_type)(int); void execute_handler(handler_type handler, int value) { handler(value); } void func(int e) { execute_handler(&(assert), e < 0); }
Compliant Solution (assert
)
In this compliant solution, the assert()
macro is wrapped in a helper function, removing the undefined behavior:
#include <assert.h> typedef void (*handler_type)(int); void execute_handler(handler_type handler, int value) { handler(value); } static void assert_handler(int value) { assert(value); } void func(int e) { execute_handler(&assert_handler, e < 0); }
Noncompliant Code Example (Redefining errno
)
Legacy code is apt to include an incorrect declaration, such as the following in this noncompliant code example:
extern int errno;
Compliant Solution (Declaring errno
)
This compliant solution demonstrates the correct way to declare errno
by including the header <errno.h>
:
#include <errno.h>
C-conforming implementations are required to declare errno
in <errno.h>
, although some historic implementations failed to do so.
Risk Assessment
Accessing objects or functions underlying the specific macros enumerated in this rule is undefined behavior.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MSC38-C | Low | Unlikely | Medium | P2 | L3 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Astrée | 24.04 | Supported, but no explicit checker | |
CodeSonar | 8.1p0 | BADMACRO.STDARG_H | Use of <stdarg.h> Feature |
Helix QAC | 2024.3 | C3437, C3475 C++3127, C++5039 | |
Parasoft C/C++test | 2023.1 | CERT_C-MSC38-a | A function-like macro shall not be invoked without all of its arguments |
R2024a | CERT C: Rule MSC38-C | Checks for predefined macro used as an object (rule fully covered) | |
RuleChecker | 24.04 | Supported, but no explicit checker |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Key here (explains table format and definitions)
Taxonomy | Taxonomy item | Relationship |
---|---|---|
CERT C | DCL37-C. Do not declare or define a reserved identifier | Prior to 2018-01-12: CERT: Unspecified Relationship |
Bibliography
ISO/IEC 9899:2011 | 7.1.4, "Use of Library Functions" |