Skip to content

Commit 8f65892

Browse files
authored
Merge pull request #867 from github/michaelrfairhurst/implement-package-generics
Implement generics package
2 parents 259dc5c + 6245f72 commit 8f65892

File tree

103 files changed

+2821
-274
lines changed

Some content is hidden

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

103 files changed

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

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

@@ -455,7 +455,7 @@ class EssentialLiteral extends EssentialExpr, Literal {
455455
if underlyingStandardType.(IntType).isSigned()
456456
then result = stlr(this)
457457
else result = utlr(this)
458-
else result = underlyingStandardType
458+
else result = getStandardType()
459459
)
460460
)
461461
}

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,27 @@
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() and
23+
// No parameter exists that is expanded in the controlling expression one or more times
24+
not exists(string parameter | macro.expansionsInsideControllingExpr(parameter) > 0)
25+
select macro,
26+
"Generic macro " + macro.getName() + " doesn't refer to a macro parameter in controlling expr '" +
27+
ctrlExpr + "'."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @id c/misra/generic-selection-not-expanded-from-a-macro
3+
* @name RULE-23-1: A generic selection should only be expanded from a macro
4+
* @description A generic selection should only be expanded from a macro.
5+
* @kind problem
6+
* @precision very-high
7+
* @problem.severity warning
8+
* @tags external/misra/id/rule-23-1
9+
* maintainability
10+
* external/misra/c/2012/amendment3
11+
* external/misra/obligation/advisory
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.misra
16+
17+
from C11GenericExpr generic, Expr ctrlExpr
18+
where
19+
not isExcluded(generic, GenericsPackage::genericSelectionNotExpandedFromAMacroQuery()) and
20+
ctrlExpr = generic.getControllingExpr() and
21+
not exists(MacroInvocation mi | mi.getAGeneratedElement() = generic.getExpr())
22+
select generic, "$@ in generic expression does not expand a macro parameter.", ctrlExpr,
23+
"Controlling expression"

0 commit comments

Comments
 (0)