Skip to content

Commit b6be03f

Browse files
authored
Merge pull request #893 from github/michaelrfairhurst/implement-package-preprocessor
Implement MISRA-C++23 Preprocesser package rules 19-0-4, 19-1-1, and 19-2-1
2 parents 82a8ce3 + 660830b commit b6be03f

39 files changed

+571
-3
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype PreprocessorQuery =
7+
TUndefOfMacroNotDefinedInFileQuery() or
8+
TInvalidTokenInDefinedOperatorQuery() or
9+
TDefinedOperatorExpandedInIfDirectiveQuery() or
10+
TNoValidIfdefGuardInHeaderQuery() or
11+
TIncludeOutsideGuardQuery()
12+
13+
predicate isPreprocessorQueryMetadata(Query query, string queryId, string ruleId, string category) {
14+
query =
15+
// `Query` instance for the `undefOfMacroNotDefinedInFile` query
16+
PreprocessorPackage::undefOfMacroNotDefinedInFileQuery() and
17+
queryId =
18+
// `@id` for the `undefOfMacroNotDefinedInFile` query
19+
"cpp/misra/undef-of-macro-not-defined-in-file" and
20+
ruleId = "RULE-19-0-4" and
21+
category = "advisory"
22+
or
23+
query =
24+
// `Query` instance for the `invalidTokenInDefinedOperator` query
25+
PreprocessorPackage::invalidTokenInDefinedOperatorQuery() and
26+
queryId =
27+
// `@id` for the `invalidTokenInDefinedOperator` query
28+
"cpp/misra/invalid-token-in-defined-operator" and
29+
ruleId = "RULE-19-1-1" and
30+
category = "required"
31+
or
32+
query =
33+
// `Query` instance for the `definedOperatorExpandedInIfDirective` query
34+
PreprocessorPackage::definedOperatorExpandedInIfDirectiveQuery() and
35+
queryId =
36+
// `@id` for the `definedOperatorExpandedInIfDirective` query
37+
"cpp/misra/defined-operator-expanded-in-if-directive" and
38+
ruleId = "RULE-19-1-1" and
39+
category = "required"
40+
or
41+
query =
42+
// `Query` instance for the `noValidIfdefGuardInHeader` query
43+
PreprocessorPackage::noValidIfdefGuardInHeaderQuery() and
44+
queryId =
45+
// `@id` for the `noValidIfdefGuardInHeader` query
46+
"cpp/misra/no-valid-ifdef-guard-in-header" and
47+
ruleId = "RULE-19-2-1" and
48+
category = "required"
49+
or
50+
query =
51+
// `Query` instance for the `includeOutsideGuard` query
52+
PreprocessorPackage::includeOutsideGuardQuery() and
53+
queryId =
54+
// `@id` for the `includeOutsideGuard` query
55+
"cpp/misra/include-outside-guard" and
56+
ruleId = "RULE-19-2-1" and
57+
category = "required"
58+
}
59+
60+
module PreprocessorPackage {
61+
Query undefOfMacroNotDefinedInFileQuery() {
62+
//autogenerate `Query` type
63+
result =
64+
// `Query` type for `undefOfMacroNotDefinedInFile` query
65+
TQueryCPP(TPreprocessorPackageQuery(TUndefOfMacroNotDefinedInFileQuery()))
66+
}
67+
68+
Query invalidTokenInDefinedOperatorQuery() {
69+
//autogenerate `Query` type
70+
result =
71+
// `Query` type for `invalidTokenInDefinedOperator` query
72+
TQueryCPP(TPreprocessorPackageQuery(TInvalidTokenInDefinedOperatorQuery()))
73+
}
74+
75+
Query definedOperatorExpandedInIfDirectiveQuery() {
76+
//autogenerate `Query` type
77+
result =
78+
// `Query` type for `definedOperatorExpandedInIfDirective` query
79+
TQueryCPP(TPreprocessorPackageQuery(TDefinedOperatorExpandedInIfDirectiveQuery()))
80+
}
81+
82+
Query noValidIfdefGuardInHeaderQuery() {
83+
//autogenerate `Query` type
84+
result =
85+
// `Query` type for `noValidIfdefGuardInHeader` query
86+
TQueryCPP(TPreprocessorPackageQuery(TNoValidIfdefGuardInHeaderQuery()))
87+
}
88+
89+
Query includeOutsideGuardQuery() {
90+
//autogenerate `Query` type
91+
result =
92+
// `Query` type for `includeOutsideGuard` query
93+
TQueryCPP(TPreprocessorPackageQuery(TIncludeOutsideGuardQuery()))
94+
}
95+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import OutOfBounds
6464
import Pointers
6565
import Preconditions1
6666
import Preconditions4
67+
import Preprocessor
6768
import Representation
6869
import Scope
6970
import SideEffects1
@@ -145,6 +146,7 @@ newtype TCPPQuery =
145146
TPointersPackageQuery(PointersQuery q) or
146147
TPreconditions1PackageQuery(Preconditions1Query q) or
147148
TPreconditions4PackageQuery(Preconditions4Query q) or
149+
TPreprocessorPackageQuery(PreprocessorQuery q) or
148150
TRepresentationPackageQuery(RepresentationQuery q) or
149151
TScopePackageQuery(ScopeQuery q) or
150152
TSideEffects1PackageQuery(SideEffects1Query q) or
@@ -226,6 +228,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
226228
isPointersQueryMetadata(query, queryId, ruleId, category) or
227229
isPreconditions1QueryMetadata(query, queryId, ruleId, category) or
228230
isPreconditions4QueryMetadata(query, queryId, ruleId, category) or
231+
isPreprocessorQueryMetadata(query, queryId, ruleId, category) or
229232
isRepresentationQueryMetadata(query, queryId, ruleId, category) or
230233
isScopeQueryMetadata(query, queryId, ruleId, category) or
231234
isSideEffects1QueryMetadata(query, queryId, ruleId, category) or

cpp/misra/src/codeql-pack.lock.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
---
22
lockVersion: 1.0.0
33
dependencies:
4+
advanced-security/qtil:
5+
version: 0.0.3
46
codeql/cpp-all:
57
version: 5.0.0
68
codeql/dataflow:

cpp/misra/src/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ license: MIT
66
dependencies:
77
codeql/common-cpp-coding-standards: '*'
88
codeql/cpp-all: 5.0.0
9+
advanced-security/qtil: 0.0.3
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* @id cpp/misra/undef-of-macro-not-defined-in-file
3+
* @name RULE-19-0-4: #undef should only be used for macros defined previously in the same file
4+
* @description Using #undef to undefine a macro that is not defined in the same file can lead to
5+
* confusion.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity warning
9+
* @tags external/misra/id/rule-19-0-4
10+
* scope/single-translation-unit
11+
* readability
12+
* maintainability
13+
* external/misra/enforcement/decidable
14+
* external/misra/obligation/advisory
15+
*/
16+
17+
import cpp
18+
import codingstandards.cpp.misra
19+
import qtil.Qtil
20+
21+
class DefOrUndef extends PreprocessorDirective {
22+
DefOrUndef() { this instanceof PreprocessorUndef or this instanceof Macro }
23+
24+
string getName() {
25+
result = this.(PreprocessorUndef).getName() or
26+
result = this.(Macro).getName()
27+
}
28+
}
29+
30+
predicate relevantNameAndFile(string name, File file) {
31+
exists(DefOrUndef m |
32+
m.getName() = name and
33+
m.getFile() = file
34+
)
35+
}
36+
37+
class StringFilePair = Qtil::Pair<string, File, relevantNameAndFile/2>::Pair;
38+
39+
/**
40+
* Defs and undefs ordered by location, grouped by name and file.
41+
*/
42+
class OrderedDefOrUndef extends Qtil::Ordered<DefOrUndef>::GroupBy<StringFilePair>::Type {
43+
override int getOrder() { result = getLocation().getStartLine() }
44+
45+
override StringFilePair getGroup() {
46+
result.getFirst() = getName() and result.getSecond() = getFile()
47+
}
48+
}
49+
50+
from OrderedDefOrUndef defOrUndef
51+
where
52+
not isExcluded(defOrUndef, PreprocessorPackage::undefOfMacroNotDefinedInFileQuery()) and
53+
// There exists an #undef for a given name and file
54+
defOrUndef instanceof PreprocessorUndef and
55+
// A previous def or undef of this name must exist in this file, and it must be a #define
56+
not defOrUndef.getPrevious() instanceof Macro
57+
select defOrUndef, "Undef of name '" + defOrUndef.getName() + "' not defined in the same file."
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @id cpp/misra/defined-operator-expanded-in-if-directive
3+
* @name RULE-19-1-1: The defined preprocessor operator shall be used appropriately
4+
* @description Macro expansions that produce the token 'defined' inside of an if directive result
5+
* in undefined behavior.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-19-1-1
10+
* scope/single-translation-unit
11+
* correctness
12+
* maintainability
13+
* external/misra/enforcement/decidable
14+
* external/misra/obligation/required
15+
*/
16+
17+
import cpp
18+
import codingstandards.cpp.misra
19+
20+
from PreprocessorIf ifDirective, MacroInvocation mi
21+
where
22+
not isExcluded(ifDirective, PreprocessorPackage::definedOperatorExpandedInIfDirectiveQuery()) and
23+
ifDirective.getLocation().subsumes(mi.getLocation()) and
24+
mi.getMacro().getBody().regexpMatch(".*defined.*")
25+
select ifDirective,
26+
"If directive contains macro expansion including the token 'defined' from macro $@, which results in undefined behavior.",
27+
mi.getMacro(), mi.getMacroName()
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @id cpp/misra/invalid-token-in-defined-operator
3+
* @name RULE-19-1-1: The defined preprocessor operator shall be used appropriately
4+
* @description Using the defined operator without an immediately following optionally parenthesized
5+
* identifier results in undefined behavior.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-19-1-1
10+
* scope/single-translation-unit
11+
* correctness
12+
* maintainability
13+
* external/misra/enforcement/decidable
14+
* external/misra/obligation/required
15+
*/
16+
17+
import cpp
18+
import codingstandards.cpp.misra
19+
20+
string idRegex() { result = "[a-zA-Z_]([a-zA-Z_0-9]*)" }
21+
22+
bindingset[body]
23+
predicate hasInvalidDefinedOperator(string body) {
24+
body.regexpMatch(".*\\bdefined" +
25+
// Contains text "defined" at a word break
26+
// Negative zero width lookahead:
27+
"(?!(" +
28+
// (group) optional whitespace followed by a valid identifier
29+
"(\\s*" + idRegex() + ")" +
30+
// or
31+
"|" +
32+
// (group) optional whitespace followed by parenthesis and valid identifier
33+
"(\\s*\\(\\s*" + idRegex() + "\\s*\\))" +
34+
// End negative zero width lookahead, match remaining text
35+
")).*")
36+
}
37+
38+
from PreprocessorIf ifDirective
39+
where
40+
not isExcluded(ifDirective, PreprocessorPackage::invalidTokenInDefinedOperatorQuery()) and
41+
hasInvalidDefinedOperator(ifDirective.getHead())
42+
select ifDirective, "Invalid use of defined operator in if directive."
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @id cpp/misra/include-outside-guard
3+
* @name RULE-19-2-1: Comments are the only content permitted outside of the scope of an include guard in a header file
4+
* @description Include directives shall be within the scope of an include guard.
5+
* @kind problem
6+
* @precision very-high
7+
* @problem.severity error
8+
* @tags external/misra/id/rule-19-2-1
9+
* scope/single-translation-unit
10+
* maintainability
11+
* correctness
12+
* external/misra/enforcement/decidable
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.cpp.misra
18+
import semmle.code.cpp.headers.MultipleInclusion
19+
20+
predicate isOutside(CorrectIncludeGuard includeGuard, Location location) {
21+
location.getFile() = includeGuard.getFile() and
22+
(
23+
location.isBefore(includeGuard.getIfndef().getLocation())
24+
or
25+
includeGuard.getEndif().getLocation().isBefore(location)
26+
)
27+
}
28+
29+
from Include include, CorrectIncludeGuard includeGuard, HeaderFile header
30+
where
31+
not isExcluded(include, PreprocessorPackage::includeOutsideGuardQuery()) and
32+
includeGuard.getFile() = header and
33+
header = include.getFile() and
34+
isOutside(includeGuard, include.getLocation())
35+
select include, "Include is outside of its header file's $@.", includeGuard.getIfndef(),
36+
"include guard"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @id cpp/misra/no-valid-ifdef-guard-in-header
3+
* @name RULE-19-2-1: Precautions shall be taken in order to prevent a header file being included more than once
4+
* @description Precautions shall be taken in order to prevent the contents of a header file being
5+
* included more than once.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-19-2-1
10+
* scope/single-translation-unit
11+
* maintainability
12+
* correctness
13+
* external/misra/enforcement/decidable
14+
* external/misra/obligation/required
15+
*/
16+
17+
import cpp
18+
import codingstandards.cpp.misra
19+
import codingstandards.cpp.rules.includeguardsnotused.IncludeGuardsNotUsed
20+
21+
class NoValidIfdefGuardInHeaderQuery extends IncludeGuardsNotUsedSharedQuery {
22+
NoValidIfdefGuardInHeaderQuery() { this = PreprocessorPackage::noValidIfdefGuardInHeaderQuery() }
23+
}

cpp/misra/test/codeql-pack.lock.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
---
22
lockVersion: 1.0.0
33
dependencies:
4+
advanced-security/qtil:
5+
version: 0.0.3
46
codeql/cpp-all:
57
version: 5.0.0
68
codeql/dataflow:

0 commit comments

Comments
 (0)