Skip to content

Commit 4befb9d

Browse files
authored
Merge pull request #99 from knewbury01/knewbury01/Preprocessor6
Package Preprocessor6
2 parents 28bf545 + d266292 commit 4befb9d

File tree

10 files changed

+192
-1
lines changed

10 files changed

+192
-1
lines changed

.vscode/tasks.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@
253253
"Preprocessor3",
254254
"Preprocessor4",
255255
"Preprocessor5",
256+
"Preprocessor6",
256257
"IntegerConversion",
257258
"Expressions",
258259
"DeadCode",
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import cpp
2+
import codingstandards.cpp.Macro
3+
import codingstandards.cpp.Naming
4+
5+
/**
6+
* Macros that cannot be replaced by functions
7+
*/
8+
abstract class IrreplaceableFunctionLikeMacro extends FunctionLikeMacro { }
9+
10+
/** A function like macro that contains the use of a stringize or tokenize operator should not be replaced by a function. */
11+
private class StringizeOrTokenizeMacro extends IrreplaceableFunctionLikeMacro {
12+
StringizeOrTokenizeMacro() {
13+
exists(TokenPastingOperator t | t.getMacro() = this) or
14+
exists(StringizingOperator s | s.getMacro() = this)
15+
}
16+
}
17+
18+
/** A standard library function like macro that should not be replaced by a function. */
19+
private class StandardLibraryFunctionLikeMacro extends IrreplaceableFunctionLikeMacro {
20+
StandardLibraryFunctionLikeMacro() { Naming::Cpp14::hasStandardLibraryMacroName(this.getName()) }
21+
}
22+
23+
/** A function like macro invocation as an `asm` argument cannot be replaced by a function. */
24+
private class AsmArgumentInvoked extends IrreplaceableFunctionLikeMacro {
25+
AsmArgumentInvoked() {
26+
any(AsmStmt s).getLocation().subsumes(this.getAnInvocation().getLocation())
27+
}
28+
}
29+
30+
/** A macro that is only invoked with constant arguments is more likely to be compile-time evaluated than a function call so do not suggest replacement. */
31+
private class OnlyConstantArgsInvoked extends IrreplaceableFunctionLikeMacro {
32+
OnlyConstantArgsInvoked() {
33+
forex(MacroInvocation mi | mi = this.getAnInvocation() |
34+
//int/float literals
35+
mi.getUnexpandedArgument(_).regexpMatch("\\d+")
36+
or
37+
//char literal or string literal, which is a literal surrounded by single quotes or double quotes
38+
mi.getUnexpandedArgument(_).regexpMatch("('[^']*'|\"[^\"]*\")")
39+
)
40+
}
41+
}
42+
43+
/** A function like macro invoked to initialize an object with static storage that cannot be replaced with a function call. */
44+
private class UsedToStaticInitialize extends IrreplaceableFunctionLikeMacro {
45+
UsedToStaticInitialize() {
46+
any(StaticStorageDurationVariable v).getInitializer().getExpr() =
47+
this.getAnInvocation().getExpr()
48+
}
49+
}
50+
51+
/** A function like macro that is called with an argument that is an operator that cannot be replaced with a function call. */
52+
private class FunctionLikeMacroWithOperatorArgument extends IrreplaceableFunctionLikeMacro {
53+
FunctionLikeMacroWithOperatorArgument() {
54+
exists(MacroInvocation mi | mi.getMacro() = this |
55+
mi.getUnexpandedArgument(_) = any(Operation op).getOperator()
56+
)
57+
}
58+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @id c/misra/function-over-function-like-macro
3+
* @name DIR-4-9: A function should be used in preference to a function-like macro where they are interchangeable
4+
* @description Using a function-like macro instead of a function can lead to unexpected program
5+
* behaviour.
6+
* @kind problem
7+
* @precision medium
8+
* @problem.severity recommendation
9+
* @tags external/misra/id/dir-4-9
10+
* external/misra/audit
11+
* maintainability
12+
* readability
13+
* external/misra/obligation/advisory
14+
*/
15+
16+
import cpp
17+
import codingstandards.c.misra
18+
import codingstandards.c.IrreplaceableFunctionLikeMacro
19+
20+
predicate partOfConstantExpr(MacroInvocation i) {
21+
exists(Expr e |
22+
e.isConstant() and
23+
not i.getExpr() = e and
24+
i.getExpr().getParent+() = e
25+
)
26+
}
27+
28+
from FunctionLikeMacro m
29+
where
30+
not isExcluded(m, Preprocessor6Package::functionOverFunctionLikeMacroQuery()) and
31+
not m instanceof IrreplaceableFunctionLikeMacro and
32+
//macros can have empty body
33+
not m.getBody().length() = 0 and
34+
//function call not allowed in a constant expression (where constant expr is parent)
35+
forall(MacroInvocation i | i = m.getAnInvocation() | not partOfConstantExpr(i))
36+
select m, "Macro used instead of a function."
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.c:6:1:6:25 | #define MACRO4(x) (x + 1) | Macro used instead of a function. |
2+
| test.c:11:1:11:48 | #define MACRO9() printf_custom("output = %d", 7) | Macro used instead of a function. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/DIR-4-9/FunctionOverFunctionLikeMacro.ql

c/misra/test/rules/DIR-4-9/test.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <assert.h>
2+
3+
#define MACRO(OP, L, R) ((L)OP(R)) // COMPLIANT
4+
#define MACRO2(L, R) (L + R) // COMPLIANT
5+
#define MACRO3(L, R) (L " " R " " L) // COMPLIANT
6+
#define MACRO4(x) (x + 1) // NON_COMPLIANT
7+
#define MACRO5(L, LR) (LR + 1) // COMPLIANT
8+
#define MACRO6(x) printf_custom("output = %d", test##x) // COMPLIANT
9+
#define MACRO7(x) #x // COMPLIANT
10+
#define MACRO8(x) "NOP" // COMPLIANT
11+
#define MACRO9() printf_custom("output = %d", 7) // NON_COMPLIANT
12+
#define MACRO10(x) // COMPLIANT
13+
#define MY_ASSERT(X) assert(X) // NON_COMPLIANT[FALSE_NEGATIVE]
14+
15+
const char a1[MACRO2(1, 1) + 6];
16+
extern printf_custom();
17+
int test1;
18+
19+
void f() {
20+
int i = MACRO(+, 1, 1);
21+
int i2 = MACRO2(7, 10);
22+
23+
static int i3 = MACRO2(1, 1);
24+
25+
char *i4 = MACRO3("prefix", "suffix");
26+
27+
int i5 = MACRO4(1);
28+
29+
int i6 = MACRO4(MACRO2(1, 1));
30+
31+
int i7 = MACRO5(1, 1);
32+
33+
MACRO6(1);
34+
35+
char *i10 = MACRO7("prefix");
36+
37+
asm(MACRO8(1));
38+
39+
MY_ASSERT(1);
40+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype Preprocessor6Query = TFunctionOverFunctionLikeMacroQuery()
7+
8+
predicate isPreprocessor6QueryMetadata(Query query, string queryId, string ruleId) {
9+
query =
10+
// `Query` instance for the `functionOverFunctionLikeMacro` query
11+
Preprocessor6Package::functionOverFunctionLikeMacroQuery() and
12+
queryId =
13+
// `@id` for the `functionOverFunctionLikeMacro` query
14+
"c/misra/function-over-function-like-macro" and
15+
ruleId = "DIR-4-9"
16+
}
17+
18+
module Preprocessor6Package {
19+
Query functionOverFunctionLikeMacroQuery() {
20+
//autogenerate `Query` type
21+
result =
22+
// `Query` type for `functionOverFunctionLikeMacro` query
23+
TQueryC(TPreprocessor6PackageQuery(TFunctionOverFunctionLikeMacroQuery()))
24+
}
25+
}

cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import Preprocessor2
2929
import Preprocessor3
3030
import Preprocessor4
3131
import Preprocessor5
32+
import Preprocessor6
3233
import SideEffects1
3334
import SideEffects2
3435
import Strings1
@@ -65,6 +66,7 @@ newtype TCQuery =
6566
TPreprocessor3PackageQuery(Preprocessor3Query q) or
6667
TPreprocessor4PackageQuery(Preprocessor4Query q) or
6768
TPreprocessor5PackageQuery(Preprocessor5Query q) or
69+
TPreprocessor6PackageQuery(Preprocessor6Query q) or
6870
TSideEffects1PackageQuery(SideEffects1Query q) or
6971
TSideEffects2PackageQuery(SideEffects2Query q) or
7072
TStrings1PackageQuery(Strings1Query q) or
@@ -101,6 +103,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId) {
101103
isPreprocessor3QueryMetadata(query, queryId, ruleId) or
102104
isPreprocessor4QueryMetadata(query, queryId, ruleId) or
103105
isPreprocessor5QueryMetadata(query, queryId, ruleId) or
106+
isPreprocessor6QueryMetadata(query, queryId, ruleId) or
104107
isSideEffects1QueryMetadata(query, queryId, ruleId) or
105108
isSideEffects2QueryMetadata(query, queryId, ruleId) or
106109
isStrings1QueryMetadata(query, queryId, ruleId) or

rule_packages/c/Preprocessor6.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"MISRA-C-2012": {
3+
"DIR-4-9": {
4+
"properties": {
5+
"obligation": "advisory"
6+
},
7+
"queries": [
8+
{
9+
"description": "Using a function-like macro instead of a function can lead to unexpected program behaviour.",
10+
"kind": "problem",
11+
"name": "A function should be used in preference to a function-like macro where they are interchangeable",
12+
"precision": "medium",
13+
"severity": "recommendation",
14+
"short_name": "FunctionOverFunctionLikeMacro",
15+
"tags": [
16+
"external/misra/audit",
17+
"maintainability",
18+
"readability"
19+
]
20+
}
21+
],
22+
"title": "A function should be used in preference to a function-like macro where they are interchangeable"
23+
}
24+
}
25+
}

rules.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ c,MISRA-C-2012,DIR-4-5,Yes,Advisory,,,Identifiers in the same name space with ov
610610
c,MISRA-C-2012,DIR-4-6,Yes,Advisory,,,typedefs that indicate size and signedness should be used in place of the basic numerical types,,Types,Hard,
611611
c,MISRA-C-2012,DIR-4-7,Yes,Required,,,"If a function returns error information, then that error information shall be tested",M0-3-2,Contracts,Import,
612612
c,MISRA-C-2012,DIR-4-8,Yes,Advisory,,,"If a pointer to a structure or union is never dereferenced within a translation unit, then the implementation of the object should be hidden",,Pointers1,Medium,
613-
c,MISRA-C-2012,DIR-4-9,Yes,Advisory,,,A function should be used in preference to a function-like macro where they are interchangeable,,Preprocessor,Medium,
613+
c,MISRA-C-2012,DIR-4-9,Yes,Advisory,,,A function should be used in preference to a function-like macro where they are interchangeable,,Preprocessor6,Medium,Audit
614614
c,MISRA-C-2012,DIR-4-10,Yes,Required,,,Precautions shall be taken in order to prevent the contents of a header file being included more than once,M16-2-3,Preprocessor2,Medium,
615615
c,MISRA-C-2012,DIR-4-11,Yes,Required,,,The validity of values passed to library functions shall be checked,,Contracts,Hard,
616616
c,MISRA-C-2012,DIR-4-12,Yes,Required,,,Dynamic memory allocation shall not be used,,Banned,Medium,

0 commit comments

Comments
 (0)