Skip to content

Navigation Menu

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 9830cc0

Browse filesBrowse files
Implement MISRA-C++23 Preprocesser package rules 19-0-4, 19-1-1, and 19-2-1.
1 parent eedca61 commit 9830cc0
Copy full SHA for 9830cc0

34 files changed

+724
-3
lines changed
+78Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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()
11+
12+
predicate isPreprocessorQueryMetadata(Query query, string queryId, string ruleId, string category) {
13+
query =
14+
// `Query` instance for the `undefOfMacroNotDefinedInFile` query
15+
PreprocessorPackage::undefOfMacroNotDefinedInFileQuery() and
16+
queryId =
17+
// `@id` for the `undefOfMacroNotDefinedInFile` query
18+
"cpp/misra/undef-of-macro-not-defined-in-file" and
19+
ruleId = "RULE-19-0-4" and
20+
category = "advisory"
21+
or
22+
query =
23+
// `Query` instance for the `invalidTokenInDefinedOperator` query
24+
PreprocessorPackage::invalidTokenInDefinedOperatorQuery() and
25+
queryId =
26+
// `@id` for the `invalidTokenInDefinedOperator` query
27+
"cpp/misra/invalid-token-in-defined-operator" and
28+
ruleId = "RULE-19-1-1" and
29+
category = "required"
30+
or
31+
query =
32+
// `Query` instance for the `definedOperatorExpandedInIfDirective` query
33+
PreprocessorPackage::definedOperatorExpandedInIfDirectiveQuery() and
34+
queryId =
35+
// `@id` for the `definedOperatorExpandedInIfDirective` query
36+
"cpp/misra/defined-operator-expanded-in-if-directive" and
37+
ruleId = "RULE-19-1-1" and
38+
category = "required"
39+
or
40+
query =
41+
// `Query` instance for the `noValidIfdefGuardInHeader` query
42+
PreprocessorPackage::noValidIfdefGuardInHeaderQuery() and
43+
queryId =
44+
// `@id` for the `noValidIfdefGuardInHeader` query
45+
"cpp/misra/no-valid-ifdef-guard-in-header" and
46+
ruleId = "RULE-19-2-1" and
47+
category = "required"
48+
}
49+
50+
module PreprocessorPackage {
51+
Query undefOfMacroNotDefinedInFileQuery() {
52+
//autogenerate `Query` type
53+
result =
54+
// `Query` type for `undefOfMacroNotDefinedInFile` query
55+
TQueryCPP(TPreprocessorPackageQuery(TUndefOfMacroNotDefinedInFileQuery()))
56+
}
57+
58+
Query invalidTokenInDefinedOperatorQuery() {
59+
//autogenerate `Query` type
60+
result =
61+
// `Query` type for `invalidTokenInDefinedOperator` query
62+
TQueryCPP(TPreprocessorPackageQuery(TInvalidTokenInDefinedOperatorQuery()))
63+
}
64+
65+
Query definedOperatorExpandedInIfDirectiveQuery() {
66+
//autogenerate `Query` type
67+
result =
68+
// `Query` type for `definedOperatorExpandedInIfDirective` query
69+
TQueryCPP(TPreprocessorPackageQuery(TDefinedOperatorExpandedInIfDirectiveQuery()))
70+
}
71+
72+
Query noValidIfdefGuardInHeaderQuery() {
73+
//autogenerate `Query` type
74+
result =
75+
// `Query` type for `noValidIfdefGuardInHeader` query
76+
TQueryCPP(TPreprocessorPackageQuery(TNoValidIfdefGuardInHeaderQuery()))
77+
}
78+
}

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

Copy file name to clipboardExpand all lines: cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import Operators
4040
import OrderOfEvaluation
4141
import OutOfBounds
4242
import Pointers
43+
import Preprocessor
4344
import Representation
4445
import Scope
4546
import SideEffects1
@@ -94,6 +95,7 @@ newtype TCPPQuery =
9495
TOrderOfEvaluationPackageQuery(OrderOfEvaluationQuery q) or
9596
TOutOfBoundsPackageQuery(OutOfBoundsQuery q) or
9697
TPointersPackageQuery(PointersQuery q) or
98+
TPreprocessorPackageQuery(PreprocessorQuery q) or
9799
TRepresentationPackageQuery(RepresentationQuery q) or
98100
TScopePackageQuery(ScopeQuery q) or
99101
TSideEffects1PackageQuery(SideEffects1Query q) or
@@ -148,6 +150,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
148150
isOrderOfEvaluationQueryMetadata(query, queryId, ruleId, category) or
149151
isOutOfBoundsQueryMetadata(query, queryId, ruleId, category) or
150152
isPointersQueryMetadata(query, queryId, ruleId, category) or
153+
isPreprocessorQueryMetadata(query, queryId, ruleId, category) or
151154
isRepresentationQueryMetadata(query, queryId, ruleId, category) or
152155
isScopeQueryMetadata(query, queryId, ruleId, category) or
153156
isSideEffects1QueryMetadata(query, queryId, ruleId, category) or
+107Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
private import codeql.util.DenseRank
2+
3+
/**
4+
* Describes how to construct a condensed list from sparse but orderable data, and how that data
5+
* should be connected, with one such list per specified division.
6+
*/
7+
signature module CondensedListSig {
8+
/**
9+
* The division specifies which items are connected into lists, with one list per division.
10+
*
11+
* For instance, if connecting variables defined in a file, the division will be the file.
12+
*/
13+
class Division;
14+
15+
/**
16+
* The class of the items to be condensed into lists.
17+
*
18+
* For instance, when connecting variables defined in a file, the items are the variables.
19+
*/
20+
class Item {
21+
string toString();
22+
}
23+
24+
/**
25+
* The index specifies the order of the items in the condensed list, and may be sparse (have
26+
* gaps).
27+
*
28+
* For instance, if connecting variables defined in a file, the index will be the line number of
29+
* the variable in the file.
30+
*
31+
* The sparse index (which may have gaps) is used to determine the ordering of the items in the
32+
* condensed list. Once the condensed list is created, the items in the list will automatically be
33+
* assigned a dense index (which has no gaps).
34+
*
35+
* There must be no duplicate indices for the same division for correctness.
36+
*/
37+
int getSparseIndex(Division d, Item l);
38+
}
39+
40+
/**
41+
* A module to take orderable data (which may not be continuous) and condense it into one or more
42+
* dense lists, with one such list per specified division.
43+
*
44+
* To instantiate this module, you need to provide a `CondensedListSig` module that
45+
* specifies the spare index and division of the items to be connected.
46+
*
47+
* For instance, to create a condensed list of variables defined in every file, you can
48+
* create a `CondensedListSig` module that specifies the file as the division and
49+
* the line number as the sparse index.
50+
*
51+
* ```ql
52+
* module ConfigFileListConfig {
53+
* class Division = File;
54+
* class Item = Variable;
55+
* int getSparseIndex(File file, Variable var) {
56+
* file = var.getLocation().getFile() and
57+
* var.getLocation().getStartLine()
58+
* }
59+
* }
60+
*
61+
* import Condense<ConfigFileListConfig>
62+
*
63+
* from Condense::ListEntry l
64+
* select l, l.getItem(), l.getDenseIndex(), l.getNext(), l.getPrev(),
65+
* ```
66+
*/
67+
module Condense<CondensedListSig Config> {
68+
newtype TList =
69+
THead(Config::Item l, Config::Division t) { denseRank(t, l) = 1 } or
70+
TCons(ListEntry prev, Config::Item l) { prev.getDenseIndex() = denseRank(prev.getDivision(), l) - 1 }
71+
72+
private module DenseRankConfig implements DenseRankInputSig2 {
73+
class Ranked = Config::Item;
74+
75+
class C = Config::Division;
76+
77+
predicate getRank = Config::getSparseIndex/2;
78+
}
79+
80+
private import DenseRank2<DenseRankConfig>
81+
82+
class ListEntry extends TList {
83+
Config::Division getDivision() {
84+
this = THead(_, result)
85+
or
86+
exists(ListEntry prev | this = TCons(prev, _) and result = prev.getDivision())
87+
}
88+
89+
string toString() {
90+
result = getItem().toString() + " [index " + getDenseIndex() + "]"
91+
}
92+
93+
Config::Item getItem() {
94+
this = THead(result, _)
95+
or
96+
this = TCons(_, result)
97+
}
98+
99+
int getDenseIndex() {
100+
result = denseRank(getDivision(), getItem())
101+
}
102+
103+
ListEntry getPrev() { this = TCons(result, _) }
104+
105+
ListEntry getNext() { result.getPrev() = this }
106+
}
107+
}
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
bindingset[this]
2+
signature class ItemSig {
3+
bindingset[this]
4+
string toString();
5+
}
6+
7+
module Pair<ItemSig A, ItemSig B> {
8+
signature predicate pred(A a, B b);
9+
10+
module Where<pred/2 ctor> {
11+
private newtype TAll = TSome(A a, B b) {
12+
ctor(a, b)
13+
}
14+
15+
class Pair extends TAll {
16+
A getFirst() {
17+
this = TSome(result, _)
18+
}
19+
20+
B getSecond() {
21+
this = TSome(_, result)
22+
}
23+
24+
string toString() {
25+
result = getFirst().toString() + ", " + getSecond().toString()
26+
}
27+
}
28+
}
29+
}
+66Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
* maintanability
13+
* external/misra/enforcement/decidable
14+
* external/misra/obligation/advisory
15+
*/
16+
17+
import cpp
18+
import codingstandards.cpp.misra
19+
import codingstandards.cpp.util.CondensedList
20+
import codingstandards.cpp.util.Pair
21+
22+
class DefOrUndef extends PreprocessorDirective {
23+
string name;
24+
25+
DefOrUndef() {
26+
name = this.(PreprocessorUndef).getName() or
27+
name = this.(Macro).getName()
28+
}
29+
30+
string getName() { result = name }
31+
}
32+
33+
predicate relevantNameAndFile(string name, File file) {
34+
exists(DefOrUndef m |
35+
m.getName() = name and
36+
m.getFile() = file
37+
)
38+
}
39+
40+
class StringFilePair = Pair<string, File>::Where<relevantNameAndFile/2>::Pair;
41+
42+
module DefUndefListConfig implements CondensedListSig {
43+
class Division = StringFilePair;
44+
45+
class Item = DefOrUndef;
46+
47+
int getSparseIndex(StringFilePair division, DefOrUndef directive) {
48+
directive.getName() = division.getFirst() and
49+
directive.getFile() = division.getSecond() and
50+
result = directive.getLocation().getStartLine()
51+
}
52+
}
53+
54+
class ListEntry = Condense<DefUndefListConfig>::ListEntry;
55+
56+
from PreprocessorUndef undef, ListEntry defUndefListEntry
57+
where
58+
not isExcluded(undef, PreprocessorPackage::undefOfMacroNotDefinedInFileQuery()) and
59+
// There exists a def or undef for a given name and file, and it is an #undef
60+
undef = defUndefListEntry.getItem() and
61+
// Exclude cases where the previous def or undef with the same name in the same file is a #define
62+
not exists(ListEntry prev |
63+
prev = defUndefListEntry.getPrev() and
64+
prev.getItem() instanceof Macro
65+
)
66+
select undef, "Undef of name '" + undef.getName() + "' not defined in the same file."
+27Lines 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::macroDefinitionContainsDefinedOperatorQuery()) 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()
+45Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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() {
21+
result = "[a-zA-Z_]([a-zA-Z_0-9]*)"
22+
}
23+
24+
bindingset[body]
25+
predicate hasInvalidDefinedOperator(string body) {
26+
body.regexpMatch(
27+
// Contains text "defined" at a word break
28+
".*\\bdefined" +
29+
// Negative zero width lookahead:
30+
"(?!(" +
31+
// (group) optional whitespace followed by a valid identifier
32+
"(\\s*" + idRegex() + ")" +
33+
// or
34+
"|" +
35+
// (group) optional whitespace followed by parenthesis and valid identifier
36+
"(\\s*\\(\\s*" + idRegex() + "\\s*\\))" +
37+
// End negative zero width lookahead, match remaining text
38+
")).*")
39+
}
40+
41+
from PreprocessorIf ifDirective
42+
where
43+
not isExcluded(ifDirective, PreprocessorPackage::invalidTokenInDefinedOperatorQuery()) and
44+
hasInvalidDefinedOperator(ifDirective.getHead())
45+
select ifDirective, "Invalid use of defined operator in if directive."

0 commit comments

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