Skip to content

Commit 515ce63

Browse files
committed
Add help files for MSC38-C and PRE32-C
1 parent 3780d35 commit 515ce63

File tree

2 files changed

+173
-4
lines changed

2 files changed

+173
-4
lines changed

c/cert/src/rules/MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.md

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,105 @@ This query implements the CERT-C rule MSC38-C:
44

55
> Do not treat a predefined identifier as an object if it might only be implemented as a macro
66
7-
## CERT
87

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+
typedef void (*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+
extern int 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).
82+
83+
<table> <tbody> <tr> <th> Rule </th> <th> Severity </th> <th> Likelihood </th> <th> Remediation Cost </th> <th> Priority </th> <th> Level </th> </tr> <tr> <td> MSC38-C </td> <td> Low </td> <td> Unlikely </td> <td> Medium </td> <td> <strong>P2</strong> </td> <td> <strong>L3</strong> </td> </tr> </tbody> </table>
84+
85+
86+
## Automated Detection
87+
88+
<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 &lt;stdarg.h&gt; 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>
100+
101+
102+
## Bibliography
103+
104+
<table> <tbody> <tr> <td> <a> ISO/IEC 9899:2011 </a> </td> <td> 7.1.4, "Use of Library Functions" </td> </tr> </tbody> </table>
105+
10106

11107
## Implementation notes
12108

c/cert/src/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.md

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,82 @@ This query implements the CERT-C rule PRE32-C:
44

55
> Do not use preprocessor directives in invocations of function-like macros
66
7-
## CERT
87

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+
void func(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.
66+
67+
<table> <tbody> <tr> <th> Rule </th> <th> Severity </th> <th> Likelihood </th> <th> Remediation Cost </th> <th> Priority </th> <th> Level </th> </tr> <tr> <td> PRE32-C </td> <td> Low </td> <td> Unlikely </td> <td> Medium </td> <td> <strong>P2</strong> </td> <td> <strong>L3</strong> </td> </tr> </tbody> </table>
68+
69+
70+
## Automated Detection
71+
72+
<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> <strong>macro-argument-hash</strong> </td> <td> Fully checked </td> </tr> <tr> <td> <a> Axivion Bauhaus Suite </a> </td> <td> 7.2.0 </td> <td> <strong>CertC-PRE32</strong> </td> <td> Fully implemented </td> </tr> <tr> <td> <a> CodeSonar </a> </td> <td> 7.0p0 </td> <td> <strong>LANG.PREPROC.MACROARG</strong> </td> <td> Preprocessing directives in macro argument </td> </tr> <tr> <td> <a> ECLAIR </a> </td> <td> 1.2 </td> <td> <strong>CC2.PRE32</strong> </td> <td> Fully implemented </td> </tr> <tr> <td> <a> Helix QAC </a> </td> <td> 2022.2 </td> <td> <strong>C0853</strong> <strong>C++1072</strong> </td> <td> </td> </tr> <tr> <td> <a> Klocwork </a> </td> <td> 2022.2 </td> <td> <strong>MISRA.EXPANSION.DIRECTIVE</strong> </td> <td> </td> </tr> <tr> <td> <a> LDRA tool suite </a> </td> <td> 9.7.1 </td> <td> <strong>341 S</strong> </td> <td> Fully implemented </td> </tr> <tr> <td> <a> Parasoft C/C++test </a> </td> <td> 2022.1 </td> <td> <strong>CERT_C-PRE32-a</strong> </td> <td> Arguments to a function-like macro shall not contain tokens that look like preprocessing directives </td> </tr> <tr> <td> <a> PC-lint Plus </a> </td> <td> 1.4 </td> <td> <strong>436, 9501</strong> </td> <td> Fully supported </td> </tr> <tr> <td> <a> Polyspace Bug Finder </a> </td> <td> R2022a </td> <td> <a> CERT C: Rule PRE32-C </a> </td> <td> Checks for preprocessor directive in macro argument (rule fully covered) </td> </tr> <tr> <td> <a> PRQA QA-C </a> </td> <td> 9.7 </td> <td> <strong>0853</strong> </td> <td> </td> </tr> <tr> <td> <a> PRQA QA-C++ </a> </td> <td> 4.4 </td> <td> <strong>1072 </strong> </td> <td> </td> </tr> <tr> <td> <a> RuleChecker </a> </td> <td> 22.04 </td> <td> <strong>macro-argument-hash</strong> </td> <td> Fully checked </td> </tr> </tbody> </table>
73+
74+
75+
## Related Vulnerabilities
76+
77+
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).
78+
79+
## Bibliography
80+
81+
<table> <tbody> <tr> <td> \[ <a> GCC Bugs </a> \] </td> <td> "Non-bugs" </td> </tr> <tr> <td> \[ <a> ISO/IEC 9899:2011 </a> \] </td> <td> 6.10.3, "Macro Replacement" </td> </tr> </tbody> </table>
82+
1083

1184
## Implementation notes
1285

0 commit comments

Comments
 (0)