You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: c/cert/src/rules/MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.md
+98-2Lines changed: 98 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -4,9 +4,105 @@ This query implements the CERT-C rule MSC38-C:
4
4
5
5
> Do not treat a predefined identifier as an object if it might only be implemented as a macro
6
6
7
-
## CERT
8
7
9
-
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py`**
8
+
9
+
## Description
10
+
11
+
The C Standard, 7.1.4 paragraph 1, \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\] states
12
+
13
+
> 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.<sup>185</sup>
14
+
15
+
16
+
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.
17
+
18
+
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](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). The macros are `assert`, `errno`, `math_errhandling`, `setjmp`, `va_arg`, `va_copy`, `va_end`, and `va_start`. These cases are described by [undefined behaviors](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) [110](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_110), [114](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_114), [122](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_122), [124](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_124), and [138](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_138). Programmers must not suppress these macros to access the underlying object or function.
19
+
20
+
## Noncompliant Code Example (assert)
21
+
22
+
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](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior).
23
+
24
+
```cpp
25
+
#include<assert.h>
26
+
27
+
typedefvoid (*handler_type)(int);
28
+
29
+
void execute_handler(handler_type handler, int value) {
30
+
handler(value);
31
+
}
32
+
33
+
void func(int e) {
34
+
execute_handler(&(assert), e < 0);
35
+
}
36
+
```
37
+
38
+
## Compliant Solution (assert)
39
+
40
+
In this compliant solution, the `assert()` macro is wrapped in a helper function, removing the [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior):
41
+
42
+
```cpp
43
+
#include <assert.h>
44
+
45
+
typedef void (*handler_type)(int);
46
+
47
+
void execute_handler(handler_type handler, int value) {
48
+
handler(value);
49
+
}
50
+
51
+
static void assert_handler(int value) {
52
+
assert(value);
53
+
}
54
+
55
+
void func(int e) {
56
+
execute_handler(&assert_handler, e < 0);
57
+
}
58
+
```
59
+
60
+
## Noncompliant Code Example (Redefining errno)
61
+
62
+
Legacy code is apt to include an incorrect declaration, such as the following in this noncompliant code example:
63
+
64
+
```cpp
65
+
externint errno;
66
+
67
+
```
68
+
69
+
## Compliant Solution (Declaring errno)
70
+
71
+
This compliant solution demonstrates the correct way to declare `errno` by including the header `<errno.h>`:
72
+
73
+
```cpp
74
+
#include<errno.h>
75
+
76
+
```
77
+
[C-conforming](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-conformingprogram)[implementations](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) are required to declare `errno` in `<errno.h>`, although some historic implementations failed to do so.
78
+
79
+
## Risk Assessment
80
+
81
+
Accessing objects or functions underlying the specific macros enumerated in this rule is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior).
<table> <tbody> <tr> <th> Tool </th> <th> Version </th> <th> Checker </th> <th> Description </th> </tr> <tr> <td> <a> Astrée </a> </td> <td> 22.04 </td> <td> </td> <td> Supported, but no explicit checker </td> </tr> <tr> <td> <a> CodeSonar </a> </td> <td> 7.0p0 </td> <td> <strong>BADMACRO.STDARG_H</strong> </td> <td> Use of <stdarg.h> Feature </td> </tr> <tr> <td> <a> Helix QAC </a> </td> <td> 2022.2 </td> <td> <strong>C3437, C3475</strong> <strong>C++3127, C++5039</strong> </td> <td> </td> </tr> <tr> <td> <a> Parasoft C/C++test </a> </td> <td> 2022.1 </td> <td> <strong>CERT_C-MSC38-a</strong> </td> <td> A function-like macro shall not be invoked without all of its arguments </td> </tr> <tr> <td> <a> Polyspace Bug Finder </a> </td> <td> R2022a </td> <td> <a> CERT C: Rule MSC38-C </a> </td> <td> Checks for predefined macro used as an object (rule fully covered) </td> </tr> <tr> <td> <a> PRQA QA-C </a> </td> <td> 9.7 </td> <td> <strong>3437, 3475</strong> </td> <td> </td> </tr> <tr> <td> <a> RuleChecker </a> </td> <td> 22.04 </td> <td> </td> <td> Supported, but no explicit checker </td> </tr> </tbody> </table>
89
+
90
+
91
+
## Related Vulnerabilities
92
+
93
+
Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+MSC38-C).
94
+
95
+
## Related Guidelines
96
+
97
+
[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions)
98
+
99
+
<table> <tbody> <tr> <th> Taxonomy </th> <th> Taxonomy item </th> <th> Relationship </th> </tr> <tr> <td> <a> CERT C </a> </td> <td> <a> DCL37-C. Do not declare or define a reserved identifier </a> </td> <td> Prior to 2018-01-12: CERT: Unspecified Relationship </td> </tr> </tbody> </table>
Copy file name to clipboardExpand all lines: c/cert/src/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.md
+75-2Lines changed: 75 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -4,9 +4,82 @@ This query implements the CERT-C rule PRE32-C:
4
4
5
5
> Do not use preprocessor directives in invocations of function-like macros
6
6
7
-
## CERT
8
7
9
-
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py`**
8
+
9
+
## Description
10
+
11
+
The arguments to a macro must not include preprocessor directives, such as `#define`, `#ifdef`, and `#include`. Doing so results in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior), according to the C Standard, 6.10.3, paragraph 11 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\]:
12
+
13
+
> 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.**
14
+
15
+
16
+
See also [undefined behavior 93](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_93).
17
+
18
+
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).
19
+
20
+
## Noncompliant Code Example
21
+
22
+
In this noncompliant code example \[[GCC Bugs](http://gcc.gnu.org/bugs.html#nonbugs_c)\], 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.
23
+
24
+
```cpp
25
+
#include<string.h>
26
+
27
+
voidfunc(const char *src) {
28
+
/* Validate the source string; calculate size */
29
+
char *dest;
30
+
/* malloc() destination string */
31
+
memcpy(dest, src,
32
+
#ifdef PLATFORM1
33
+
12
34
+
#else
35
+
24
36
+
#endif
37
+
);
38
+
/* ... */
39
+
}
40
+
41
+
```
42
+
43
+
## Compliant Solution
44
+
45
+
In this compliant solution \[[GCC Bugs](http://gcc.gnu.org/bugs.html#nonbugs_c)\], the appropriate call to `memcpy()` is determined outside the function call:
46
+
47
+
```cpp
48
+
#include <string.h>
49
+
50
+
void func(const char *src) {
51
+
/* Validate the source string; calculate size */
52
+
char *dest;
53
+
/* malloc() destination string */
54
+
#ifdef PLATFORM1
55
+
memcpy(dest, src, 12);
56
+
#else
57
+
memcpy(dest, src, 24);
58
+
#endif
59
+
/* ... */
60
+
}
61
+
```
62
+
63
+
## Risk Assessment
64
+
65
+
Including preprocessor directives in macro arguments is undefined behavior.
Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+PRE32-C).
0 commit comments