Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3bb8b61

Browse filesBrowse files
committed
Preprocessor5: add Rule PRE32-C
1 parent 2b0527b commit 3bb8b61
Copy full SHA for 3bb8b61

File tree

Expand file treeCollapse file tree

11 files changed

+194
-26
lines changed
Filter options
Expand file treeCollapse file tree

11 files changed

+194
-26
lines changed
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# PRE32-C: Do not use preprocessor directives in invocations of function-like macros
2+
3+
This query implements the CERT-C rule PRE32-C:
4+
5+
> Do not use preprocessor directives in invocations of function-like macros
6+
7+
## CERT
8+
9+
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
10+
11+
## Implementation notes
12+
13+
None
14+
15+
## References
16+
17+
* CERT-C: [PRE32-C: Do not use preprocessor directives in invocations of function-like macros](https://wiki.sei.cmu.edu/confluence/display/c)
+58Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* @id c/cert/macro-or-function-args-contain-hash-token
3+
* @name PRE32-C: Do not use preprocessor directives in invocations of function-like macros
4+
* @description Arguments to a function-like macros shall not contain tokens that look like
5+
* pre-processing directives or else behaviour after macro expansion is unpredictable.
6+
* This rule applies to functions as well in case they are implemented using macros.
7+
* @kind problem
8+
* @precision high
9+
* @problem.severity warning
10+
* @tags external/cert/id/pre32-c
11+
* readability
12+
* correctness
13+
* external/cert/obligation/rule
14+
*/
15+
16+
import cpp
17+
import codingstandards.c.cert
18+
import codingstandards.cpp.PreprocessorDirective
19+
20+
pragma[noinline]
21+
predicate isFunctionInvocationLocation(FunctionCall call, File f, int startline, int endline) {
22+
call.getLocation().hasLocationInfo(f.getAbsolutePath(), startline, _, _, _) and
23+
//for all function calls the closest location heurisitc we have for end line is the next node in cfg
24+
call.getASuccessor().getLocation().hasLocationInfo(f.getAbsolutePath(), endline, _, _, _)
25+
}
26+
27+
PreprocessorDirective isLocatedInAFunctionInvocation(FunctionCall c) {
28+
exists(PreprocessorDirective p, File f, int startCall, int endCall |
29+
isFunctionInvocationLocation(c, f, startCall, endCall) and
30+
exists(int startLine, int endLine | isPreprocDirectiveLine(p, f, startLine, endLine) |
31+
startCall < startLine and
32+
startCall < endLine and
33+
endLine <= endCall and
34+
endLine <= endCall
35+
) and
36+
result = p
37+
)
38+
}
39+
40+
from PreprocessorDirective p, string msg
41+
where
42+
not isExcluded(p, Preprocessor5Package::macroOrFunctionArgsContainHashTokenQuery()) and
43+
exists(FunctionCall c |
44+
p = isLocatedInAFunctionInvocation(c) and
45+
//if this is actually a function in a macro ignore it because it will still be seen in the macro condition
46+
not c.isInMacroExpansion() and
47+
msg =
48+
"Invocation of function " + c.getTarget().getName() + " includes a token \"" + p +
49+
"\" that could be confused for an argument preprocessor directive."
50+
)
51+
or
52+
exists(MacroInvocation m |
53+
p = isLocatedInAMacroInvocation(m) and
54+
msg =
55+
"Invocation of macro " + m.getMacroName() + " includes a token \"" + p +
56+
"\" that could be confused for an argument preprocessor directive."
57+
)
58+
select p, msg
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| test.c:9:1:9:19 | #if NOTDEFINEDMACRO | Invocation of macro MACROFUNCTION includes a token "#if NOTDEFINEDMACRO" that could be confused for an argument preprocessor directive. |
2+
| test.c:11:1:11:5 | #else | Invocation of macro MACROFUNCTION includes a token "#else" that could be confused for an argument preprocessor directive. |
3+
| test.c:13:1:13:6 | #endif | Invocation of macro MACROFUNCTION includes a token "#endif" that could be confused for an argument preprocessor directive. |
4+
| test.c:20:1:20:16 | #ifdef SOMEMACRO | Invocation of function memcpy includes a token "#ifdef SOMEMACRO" that could be confused for an argument preprocessor directive. |
5+
| test.c:22:1:22:5 | #else | Invocation of function memcpy includes a token "#else" that could be confused for an argument preprocessor directive. |
6+
| test.c:24:1:24:6 | #endif | Invocation of function memcpy includes a token "#endif" that could be confused for an argument preprocessor directive. |
7+
| test.c:27:1:27:8 | #if TEST | Invocation of function memcpy includes a token "#if TEST" that could be confused for an argument preprocessor directive. |
8+
| test.c:28:1:28:6 | #endif | Invocation of function memcpy includes a token "#endif" that could be confused for an argument preprocessor directive. |
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/PRE32-C/MacroOrFunctionArgsContainHashToken.ql

‎c/cert/test/rules/PRE32-C/test.c

Copy file name to clipboard
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
#include <string.h>
3+
#define MACROFUNCTION(X) strlen(X)
4+
5+
void func(const char *src) {
6+
char *dest;
7+
8+
MACROFUNCTION(
9+
#if NOTDEFINEDMACRO // NON_COMPLIANT
10+
"longstringtest!test!"
11+
#else // NON_COMPLIANT
12+
"shortstring"
13+
#endif // NON_COMPLIANT
14+
);
15+
16+
MACROFUNCTION("alright"); // COMPLIANT
17+
memcpy(dest, src, 12); // COMPLIANT
18+
19+
memcpy(dest, src,
20+
#ifdef SOMEMACRO // NON_COMPLIANT
21+
12
22+
#else // NON_COMPLIANT
23+
24
24+
#endif // NON_COMPLIANT
25+
);
26+
27+
#if TEST // COMPLIANT[FALSE_POSITIVE]
28+
#endif // COMPLIANT[FALSE_POSITIVE]
29+
}

‎cpp/common/src/codingstandards/cpp/Macro.qll

Copy file name to clipboardExpand all lines: cpp/common/src/codingstandards/cpp/Macro.qll
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,9 @@ class StringizingOperator extends TStringizingOperator {
6363

6464
string toString() { result = getMacro().toString() }
6565
}
66+
67+
68+
pragma[noinline]
69+
predicate isMacroInvocationLocation(MacroInvocation mi, File f, int startChar, int endChar) {
70+
mi.getActualLocation().charLoc(f, startChar, endChar)
71+
}
+32Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import cpp
2+
import codingstandards.cpp.Macro
3+
4+
pragma[noinline]
5+
predicate isPreprocDirectiveLocation(PreprocessorDirective pd, File f, int startChar) {
6+
pd.getLocation().charLoc(f, startChar, _)
7+
}
8+
9+
pragma[noinline]
10+
predicate isPreprocDirectiveLine(PreprocessorDirective pd, File f, int startline, int endline) {
11+
pd.getLocation().hasLocationInfo(f.getAbsolutePath(), startline, _, endline, _)
12+
}
13+
14+
PreprocessorDirective isLocatedInAMacroInvocation(MacroInvocation m) {
15+
exists(PreprocessorDirective p |
16+
// There is not sufficient information in the database for nested macro invocations, because
17+
// the location of nested macros and preprocessor directives are all set to the location of the
18+
// outermost macro invocation
19+
not exists(m.getParentInvocation()) and
20+
exists(File f, int startChar, int endChar |
21+
isMacroInvocationLocation(m, f, startChar, endChar) and
22+
exists(int lStart | isPreprocDirectiveLocation(p, f, lStart) |
23+
// If the start location of the preprocessor directive is after the start of the macro
24+
// invocation, and before the end, it must be within the macro invocation
25+
// Note: it's critical to use startChar < lStart, not startChar <= lStart, because the
26+
// latter will include preprocessor directives which occur in nested macro invocations
27+
startChar < lStart and lStart < endChar
28+
)
29+
) and
30+
result = p
31+
)
32+
}

‎cpp/common/src/codingstandards/cpp/exclusions/c/Preprocessor5.qll

Copy file name to clipboardExpand all lines: cpp/common/src/codingstandards/cpp/exclusions/c/Preprocessor5.qll
+18-1Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,19 @@ import cpp
33
import RuleMetadata
44
import codingstandards.cpp.exclusions.RuleMetadata
55

6-
newtype Preprocessor5Query = TMacroParameterNotEnclosedInParenthesesCQueryQuery()
6+
newtype Preprocessor5Query =
7+
TMacroOrFunctionArgsContainHashTokenQuery() or
8+
TMacroParameterNotEnclosedInParenthesesCQueryQuery()
79

810
predicate isPreprocessor5QueryMetadata(Query query, string queryId, string ruleId) {
11+
query =
12+
// `Query` instance for the `macroOrFunctionArgsContainHashToken` query
13+
Preprocessor5Package::macroOrFunctionArgsContainHashTokenQuery() and
14+
queryId =
15+
// `@id` for the `macroOrFunctionArgsContainHashToken` query
16+
"c/cert/macro-or-function-args-contain-hash-token" and
17+
ruleId = "PRE32-C"
18+
or
919
query =
1020
// `Query` instance for the `macroParameterNotEnclosedInParenthesesCQuery` query
1121
Preprocessor5Package::macroParameterNotEnclosedInParenthesesCQueryQuery() and
@@ -16,6 +26,13 @@ predicate isPreprocessor5QueryMetadata(Query query, string queryId, string ruleI
1626
}
1727

1828
module Preprocessor5Package {
29+
Query macroOrFunctionArgsContainHashTokenQuery() {
30+
//autogenerate `Query` type
31+
result =
32+
// `Query` type for `macroOrFunctionArgsContainHashToken` query
33+
TQueryC(TPreprocessor5PackageQuery(TMacroOrFunctionArgsContainHashTokenQuery()))
34+
}
35+
1936
Query macroParameterNotEnclosedInParenthesesCQueryQuery() {
2037
//autogenerate `Query` type
2138
result =

‎cpp/common/src/codingstandards/cpp/rules/preprocessingdirectivewithinmacroargument/PreprocessingDirectiveWithinMacroArgument.qll

Copy file name to clipboardExpand all lines: cpp/common/src/codingstandards/cpp/rules/preprocessingdirectivewithinmacroargument/PreprocessingDirectiveWithinMacroArgument.qll
+2-24Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,16 @@
55
import cpp
66
import codingstandards.cpp.Customizations
77
import codingstandards.cpp.Exclusions
8+
import codingstandards.cpp.PreprocessorDirective
89

910
abstract class PreprocessingDirectiveWithinMacroArgumentSharedQuery extends Query { }
1011

1112
Query getQuery() { result instanceof PreprocessingDirectiveWithinMacroArgumentSharedQuery }
1213

13-
pragma[noinline]
14-
predicate isMacroInvocationLocation(MacroInvocation mi, File f, int startChar, int endChar) {
15-
mi.getActualLocation().charLoc(f, startChar, endChar)
16-
}
17-
18-
pragma[noinline]
19-
predicate isPreprocDirectiveLocation(PreprocessorDirective pd, File f, int startChar) {
20-
pd.getLocation().charLoc(f, startChar, _)
21-
}
22-
2314
query predicate problems(MacroInvocation m, string message) {
2415
not isExcluded(m, getQuery()) and
2516
exists(PreprocessorDirective p |
26-
// There is not sufficient information in the database for nested macro invocations, because
27-
// the location of nested macros and preprocessor directives are all set to the location of the
28-
// outermost macro invocation
29-
not exists(m.getParentInvocation()) and
30-
exists(File f, int startChar, int endChar |
31-
isMacroInvocationLocation(m, f, startChar, endChar) and
32-
exists(int lStart | isPreprocDirectiveLocation(p, f, lStart) |
33-
// If the start location of the preprocessor directive is after the start of the macro
34-
// invocation, and before the end, it must be within the macro invocation
35-
// Note: it's critical to use startChar < lStart, not startChar <= lStart, because the
36-
// latter will include preprocessor directives which occur in nested macro invocations
37-
startChar < lStart and lStart < endChar
38-
)
39-
) and
17+
p = isLocatedInAMacroInvocation(m) and
4018
message =
4119
"Invocation of macro " + m.getMacroName() + " includes a token \"" + p +
4220
"\" that could be confused for an argument preprocessor directive."

‎rule_packages/c/Preprocessor5.json

Copy file name to clipboardExpand all lines: rule_packages/c/Preprocessor5.json
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,26 @@
11
{
2+
"CERT-C": {
3+
"PRE32-C": {
4+
"properties": {
5+
"obligation": "rule"
6+
},
7+
"queries": [
8+
{
9+
"description": "Arguments to a function-like macros shall not contain tokens that look like pre-processing directives or else behaviour after macro expansion is unpredictable. This rule applies to functions as well in case they are implemented using macros.",
10+
"kind": "problem",
11+
"name": "Do not use preprocessor directives in invocations of function-like macros",
12+
"precision": "high",
13+
"severity": "warning",
14+
"short_name": "MacroOrFunctionArgsContainHashToken",
15+
"tags": [
16+
"readability",
17+
"correctness"
18+
]
19+
}
20+
],
21+
"title": "Do not use preprocessor directives in invocations of function-like macros"
22+
}
23+
},
224
"MISRA-C-2012": {
325
"RULE-20-7": {
426
"properties": {

‎rules.csv

Copy file name to clipboardExpand all lines: rules.csv
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ c,CERT-C,POS53-C,OutOfScope,Rule,,,Do not use more than one mutex for concurrent
587587
c,CERT-C,POS54-C,OutOfScope,Rule,,,Detect and handle POSIX library errors,,,,
588588
c,CERT-C,PRE30-C,No,Rule,,,Do not create a universal character name through concatenation,,,Medium,
589589
c,CERT-C,PRE31-C,Yes,Rule,,,Avoid side effects in arguments to unsafe macros,RULE-13-2,SideEffects,Medium,
590-
c,CERT-C,PRE32-C,Yes,Rule,,,Do not use preprocessor directives in invocations of function-like macros,,Preprocessor,Hard,
590+
c,CERT-C,PRE32-C,Yes,Rule,,,Do not use preprocessor directives in invocations of function-like macros,,Preprocessor5,Hard,
591591
c,CERT-C,SIG30-C,Yes,Rule,,,Call only asynchronous-safe functions within signal handlers,,Contracts,Medium,
592592
c,CERT-C,SIG31-C,Yes,Rule,,,Do not access shared objects in signal handlers,,Contracts,Medium,
593593
c,CERT-C,SIG34-C,Yes,Rule,,,Do not call signal() from within interruptible signal handlers,,Contracts,Medium,

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.