Skip to content

Commit 64b7684

Browse files
Implement generics package
1 parent 4ac7c5c commit 64b7684

File tree

101 files changed

+2846
-263
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+2846
-263
lines changed

c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
import cpp
1515
import codingstandards.c.cert
16-
import codingstandards.cpp.Pointers
16+
import codingstandards.cpp.types.Pointers
1717
import semmle.code.cpp.dataflow.TaintTracking
1818
import ScaledIntegerPointerArithmeticFlow::PathGraph
1919

c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql

+3-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import cpp
1818
import codingstandards.c.cert
19-
import codingstandards.cpp.Compatible
19+
import codingstandards.cpp.types.Compatible
2020
import ExternalIdentifiers
2121

2222
from ExternalIdentifiers d, FunctionDeclarationEntry f1, FunctionDeclarationEntry f2
@@ -29,12 +29,10 @@ where
2929
f1.getName() = f2.getName() and
3030
(
3131
//return type check
32-
not typesCompatible(f1.getType(), f2.getType())
32+
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig>::equalReturnTypes(f1, f2)
3333
or
3434
//parameter type check
35-
parameterTypesIncompatible(f1, f2)
36-
or
37-
not f1.getNumberOfParameters() = f2.getNumberOfParameters()
35+
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig>::equalParameterTypes(f1, f2)
3836
) and
3937
// Apply ordering on start line, trying to avoid the optimiser applying this join too early
4038
// in the pipeline
+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import cpp
2+
import codingstandards.cpp.Macro
3+
import codingstandards.cpp.MatchingParenthesis
4+
5+
string genericRegexp() { result = ".*_Generic\\s*\\(\\s*(.+),.*" }
6+
7+
bindingset[input]
8+
string deparenthesize(string input) {
9+
input = "(" + result + ")" and
10+
result = input.substring(1, input.length() - 1)
11+
}
12+
13+
14+
class GenericMacro extends Macro {
15+
string ctrlExpr;
16+
17+
GenericMacro() { ctrlExpr = getBody().regexpCapture(genericRegexp(), 1).trim() }
18+
19+
string getAParameter() { result = this.(FunctionLikeMacro).getAParameter() }
20+
21+
string getControllingExprString() {
22+
if exists(string s | s = deparenthesize(ctrlExpr))
23+
then result = deparenthesize(ctrlExpr).trim()
24+
else result = ctrlExpr
25+
}
26+
27+
/**
28+
* Whether the controlling expression of the `_Generic` expr in this macro's controlling
29+
* expression refers to one of this macro's parameters.
30+
*/
31+
predicate hasControllingExprFromMacroParameter() {
32+
getControllingExprString().matches(getAParameter())
33+
}
34+
}
35+
36+
class GenericMacroString extends string {
37+
GenericMacroString() { this = any(Macro m).getBody() and this.matches("%_Generic%") }
38+
}
39+
40+
import MatchingParenthesis<GenericMacroString>
41+
42+
class ParsedGenericMacro extends Macro {
43+
ParsedRoot macroBody;
44+
Parsed genericBody;
45+
string beforeGenericBody;
46+
string afterGenericBody;
47+
48+
ParsedGenericMacro() {
49+
macroBody.getInputString() = this.getBody() and
50+
exists(ParsedText genericText |
51+
genericText.getText().matches("%_Generic%") and
52+
genericBody = genericText.getParent().getChild(genericText.getChildIdx() + 1) and
53+
genericBody.getRoot() = macroBody
54+
) and
55+
beforeGenericBody =
56+
textFrom(macroBody.getStartToken(), genericBody.getStartToken().getPrevious()) and
57+
(
58+
if exists(genericBody.getEndToken().getNext())
59+
then afterGenericBody = textFrom(genericBody.getEndToken().getNext(), macroBody.getEndToken())
60+
else afterGenericBody = ""
61+
)
62+
}
63+
64+
string getAParameter() {
65+
result = this.(FunctionLikeMacro).getAParameter()
66+
}
67+
68+
int getAParsedGenericCommaSeparatorOffset() {
69+
exists(ParsedText text |
70+
text.getParent() = genericBody and
71+
result = text.getStartToken().getStartPos() + text.getText().indexOf(",")
72+
)
73+
}
74+
75+
int getAParsedGenericColonSeparatorOffset() {
76+
exists(ParsedText text |
77+
text.getParent() = genericBody and
78+
result = text.getStartToken().getStartPos() + text.getText().indexOf(":")
79+
)
80+
}
81+
82+
int getParsedGenericCommaSeparatorOffset(int i) {
83+
result = rank[i](int index | index = getAParsedGenericCommaSeparatorOffset())
84+
}
85+
86+
bindingset[start, end]
87+
int getParsedGenericColon(int start, int end) {
88+
result =
89+
min(int offset |
90+
offset = getAParsedGenericColonSeparatorOffset() and
91+
offset >= start and
92+
offset <= end
93+
)
94+
}
95+
96+
predicate hasParsedFullSelectionRange(int idx, int start, int end) {
97+
idx = 1 and
98+
start = genericBody.getStartToken().getEndPos() and
99+
end = getParsedGenericCommaSeparatorOffset(idx)
100+
or
101+
not exists(getParsedGenericCommaSeparatorOffset(idx)) and
102+
start = getParsedGenericCommaSeparatorOffset(idx - 1) and
103+
end = genericBody.getEndToken().getStartPos()
104+
or
105+
start = getParsedGenericCommaSeparatorOffset(idx - 1) and
106+
end = getParsedGenericCommaSeparatorOffset(idx)
107+
}
108+
109+
string getSelectionString(int idx) {
110+
exists(int start, int rawStart, int end |
111+
hasParsedFullSelectionRange(idx, rawStart, end) and
112+
(
113+
if exists(getParsedGenericColon(rawStart, end))
114+
then start = getParsedGenericColon(rawStart, end)
115+
else start = rawStart
116+
) and
117+
result = genericBody.getInputString().substring(start, end)
118+
)
119+
}
120+
121+
string getControllingExprString() {
122+
result = getSelectionString(1)
123+
}
124+
125+
bindingset[str, word]
126+
private int countWordInString(string word, string str) {
127+
result =
128+
max(int occurrence |
129+
exists(str.regexpFind("\\b" + word + "\\b", occurrence, _)) or occurrence = -1
130+
|
131+
occurrence + 1
132+
)
133+
}
134+
135+
int expansionsOutsideExpr(string parameter) {
136+
parameter = getAParameter() and
137+
result =
138+
countWordInString(parameter, beforeGenericBody) +
139+
countWordInString(parameter, afterGenericBody)
140+
}
141+
142+
int expansionsInsideSelection(string parameter, int idx) {
143+
parameter = getAParameter() and
144+
result = countWordInString(parameter, getSelectionString(idx))
145+
}
146+
147+
int expansionsInsideControllingExpr(string parameter) {
148+
result = expansionsInsideSelection(parameter, 1)
149+
}
150+
151+
int expansionsInsideAssociation(string parameter, int idx) {
152+
not idx = 0 and
153+
result = expansionsInsideSelection(parameter, idx + 1)
154+
}
155+
}

c/common/src/codingstandards/c/OutOfBounds.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
import cpp
8-
import codingstandards.cpp.Pointers
8+
import codingstandards.cpp.types.Pointers
99
import codingstandards.c.Variable
1010
import codingstandards.cpp.Allocations
1111
import codingstandards.cpp.Overflow

c/common/src/codingstandards/c/UndefinedBehavior.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import cpp
2-
import codingstandards.cpp.Pointers
2+
import codingstandards.cpp.types.Pointers
33
import codingstandards.cpp.UndefinedBehavior
44

55
/**

c/misra/src/codingstandards/c/misra/EssentialTypes.qll

+9-9
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,14 @@ EssentialTypeCategory getEssentialTypeCategory(Type type) {
164164
*/
165165
pragma[nomagic]
166166
Type getEssentialType(Expr e) {
167-
if e.hasExplicitConversion()
168-
then
169-
if e.getConversion() instanceof ParenthesisExpr
170-
then
171-
if e.getConversion().(ParenthesisExpr).hasExplicitConversion()
172-
then result = e.getConversion().(ParenthesisExpr).getConversion().getType()
173-
else result = e.getConversion().(ParenthesisExpr).getExpr().(EssentialExpr).getEssentialType()
174-
else result = e.getConversion().getType()
167+
if e.hasConversion()
168+
then result = getEssentialTypeOfConversion(e.getFullyConverted())
169+
else result = e.(EssentialExpr).getEssentialType()
170+
}
171+
172+
Type getEssentialTypeOfConversion(Expr e) {
173+
if e.(Conversion).isImplicit() or e instanceof ParenthesisExpr or e instanceof C11GenericExpr
174+
then result = getEssentialTypeOfConversion(e.(Conversion).getExpr())
175175
else result = e.(EssentialExpr).getEssentialType()
176176
}
177177

@@ -446,7 +446,7 @@ class EssentialLiteral extends EssentialExpr, Literal {
446446
if underlyingStandardType.(IntType).isSigned()
447447
then result = stlr(this)
448448
else result = utlr(this)
449-
else result = underlyingStandardType
449+
else result = getStandardType()
450450
)
451451
)
452452
}

c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import cpp
1616
import codingstandards.c.misra
17-
import codingstandards.cpp.Pointers
17+
import codingstandards.cpp.types.Pointers
1818

1919
from CStyleCast cast, Type type, Type newType
2020
where

c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import cpp
1616
import codingstandards.c.misra
17-
import codingstandards.cpp.Pointers
17+
import codingstandards.cpp.types.Pointers
1818
import codingstandards.cpp.Type
1919

2020
from Cast cast, Type type, Type newType

c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
import cpp
1717
import codingstandards.c.misra
18-
import codingstandards.cpp.Pointers
18+
import codingstandards.cpp.types.Pointers
1919

2020
from CStyleCast cast, Type baseTypeFrom, Type baseTypeTo
2121
where

c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import cpp
1616
import codingstandards.c.misra
1717
import codingstandards.cpp.Macro
18-
import codingstandards.cpp.Pointers
18+
import codingstandards.cpp.types.Pointers
1919

2020
MacroInvocation getAMacroInvocation(CStyleCast cast) { result.getAnExpandedElement() = cast }
2121

c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import cpp
1616
import codingstandards.c.misra
17-
import codingstandards.cpp.Pointers
17+
import codingstandards.cpp.types.Pointers
1818

1919
from Cast cast, VoidPointerType type, PointerToObjectType newType
2020
where

c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import cpp
1616
import codingstandards.c.misra
17-
import codingstandards.cpp.Pointers
17+
import codingstandards.cpp.types.Pointers
1818

1919
from CStyleCast cast, Type typeFrom, Type typeTo
2020
where

c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import cpp
1616
import codingstandards.c.misra
17-
import codingstandards.cpp.Pointers
17+
import codingstandards.cpp.types.Pointers
1818

1919
class MisraNonIntegerArithmeticType extends Type {
2020
MisraNonIntegerArithmeticType() {

c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
import cpp
1515
import codingstandards.c.misra
16-
import codingstandards.cpp.Pointers
16+
import codingstandards.cpp.types.Pointers
1717
import codingstandards.cpp.Type
1818

1919
from Zero zero, Expr e, string type

c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import cpp
1818
import codingstandards.c.misra
19-
import codingstandards.cpp.VariablyModifiedTypes
19+
import codingstandards.cpp.types.VariablyModifiedTypes
2020

2121
from VmtDeclarationEntry v, string declstr, string adjuststr, string relationstr
2222
where

c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
import cpp
1717
import codingstandards.c.misra
18-
import codingstandards.cpp.TypeUses
18+
import codingstandards.cpp.types.Uses
1919

2020
from UserType s
2121
where

c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ from ReportDeadObject report
2020
where
2121
not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionQuery()) and
2222
not report.hasAttrUnused()
23-
select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(),
23+
select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocatable(),
2424
report.getOptionalPlaceholderMessage()

c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ from ReportDeadObject report
2222
where
2323
not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionStrictQuery()) and
2424
report.hasAttrUnused()
25-
select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(),
25+
select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocatable(),
2626
report.getOptionalPlaceholderMessage()

c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
import cpp
1515
import codingstandards.c.misra
16-
import codingstandards.cpp.Pointers
16+
import codingstandards.cpp.types.Pointers
1717

1818
class MemCmpMoveCpy extends Function {
1919
// Couldn't extend BuiltInFunction because it misses `memcmp`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @id c/misra/generic-selection-doesnt-depend-on-macro-argument
3+
* @name RULE-23-1: A generic selection should depend on the type of a macro argument
4+
* @description A generic selection should depend on the type of a macro argument.
5+
* @kind problem
6+
* @precision high
7+
* @problem.severity warning
8+
* @tags external/misra/id/rule-23-1
9+
* correctness
10+
* maintainability
11+
* external/misra/c/2012/amendment3
12+
* external/misra/obligation/advisory
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
import codingstandards.c.Generic
18+
19+
from ParsedGenericMacro macro, string ctrlExpr
20+
where
21+
not isExcluded(macro, GenericsPackage::genericSelectionDoesntDependOnMacroArgumentQuery()) and
22+
ctrlExpr = macro.getControllingExprString().trim() and
23+
not macro.expansionsInsideControllingExpr(_) > 0
24+
select macro,
25+
"Generic macro " + macro.getName() + " uses controlling expr " + ctrlExpr +
26+
", which doesn't match any macro parameter."

0 commit comments

Comments
 (0)