Skip to content

Commit 4ee7629

Browse files
Deduplicate and filter results, improve messages, handle performance issue
1 parent 59ebba0 commit 4ee7629

6 files changed

+207
-281
lines changed

c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql

+49-20
Original file line numberDiff line numberDiff line change
@@ -73,44 +73,73 @@ module InvalidInfinityUsage implements DataFlow::ConfigSig {
7373
}
7474

7575
predicate isSink(DataFlow::Node node) {
76+
node instanceof InvalidInfinityUsage and
7677
(
7778
// Require that range analysis finds this value potentially infinite, to avoid false positives
7879
// in the presence of guards. This may induce false negatives.
79-
exprMayEqualInfinity(node.asExpr(), _) or
80+
exprMayEqualInfinity(node.asExpr(), _)
81+
or
8082
// Unanalyzable expressions are not checked against range analysis, which assumes a finite
8183
// range.
8284
not RestrictedRangeAnalysis::analyzableExpr(node.asExpr())
83-
) and
84-
(
85-
// Case 2: NaNs and infinities shall not be cast to integers
86-
exists(Conversion c |
87-
node.asExpr() = c.getUnconverted() and
88-
c.getExpr().getType() instanceof FloatingPointType and
89-
c.getType() instanceof IntegralType
90-
)
91-
or
92-
// Case 3: Infinities shall not underflow or otherwise produce finite values
93-
exists(BinaryOperation op |
94-
node.asExpr() = op.getRightOperand() and
95-
op.getOperator() = ["/", "%"]
96-
)
9785
)
9886
}
9987
}
10088

89+
class InvalidInfinityUsage extends DataFlow::Node {
90+
string description;
91+
string infinityDescription;
92+
93+
InvalidInfinityUsage() {
94+
// Case 2: NaNs and infinities shall not be cast to integers
95+
exists(Conversion c |
96+
asExpr() = c.getUnconverted() and
97+
c.getExpr().getType() instanceof FloatingPointType and
98+
c.getType() instanceof IntegralType and
99+
description = "$@ casted to integer." and
100+
infinityDescription = "Possibly infinite float value"
101+
)
102+
or
103+
// Case 3: Infinities shall not underflow or otherwise produce finite values
104+
exists(BinaryOperation op |
105+
asExpr() = op.getRightOperand() and
106+
op.getOperator() = "/" and
107+
description = "Division operation may silently underflow and produce zero, as the divisor $@." and
108+
infinityDescription = "may be an infinite float value"
109+
)
110+
}
111+
112+
string getDescription() { result = description }
113+
114+
string getInfinityDescription() { result = infinityDescription }
115+
}
116+
101117
module InvalidInfinityFlow = DataFlow::Global<InvalidInfinityUsage>;
102118

103119
import InvalidInfinityFlow::PathGraph
104120

105121
from
106122
Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink,
107-
string msg, string sourceString
123+
InvalidInfinityUsage usage, Expr sourceExpr, Element extra, string extraString
108124
where
109125
elem = MacroUnwrapper<Expr>::unwrapElement(sink.getNode().asExpr()) and
126+
not InvalidInfinityFlow::PathGraph::edges(_, source, _, _) and
110127
not isExcluded(elem, FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery()) and
128+
not sourceExpr.isFromTemplateInstantiation(_) and
129+
not usage.asExpr().isFromTemplateInstantiation(_) and
130+
usage = sink.getNode() and
131+
sourceExpr = source.getNode().asExpr() and
132+
InvalidInfinityFlow::flow(source.getNode(), usage) and
111133
(
112-
InvalidInfinityFlow::flow(source.getNode(), sink.getNode()) and
113-
msg = "Invalid usage of possible $@." and
114-
sourceString = "infinity"
134+
if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction()
135+
then
136+
extraString = usage.getInfinityDescription() + " computed in function " + sourceExpr.getEnclosingFunction().getName()
137+
and extra = sourceExpr.getEnclosingFunction()
138+
else (
139+
extra = sourceExpr and
140+
if sourceExpr instanceof DivExpr
141+
then extraString = usage.getInfinityDescription() + " from division by zero"
142+
else extraString = usage.getInfinityDescription()
143+
)
115144
)
116-
select elem, source, sink, msg, source, sourceString
145+
select elem, source, sink, usage.getDescription(), extra, extraString

c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql

+47-21
Original file line numberDiff line numberDiff line change
@@ -40,43 +40,43 @@ class InvalidOperationExpr extends BinaryOperation {
4040
exprMayEqualInfinity(getLeftOperand(), sign) and
4141
exprMayEqualInfinity(getRightOperand(), sign.booleanNot())
4242
) and
43-
reason = "possible addition of infinity and negative infinity"
43+
reason = "from addition of infinity and negative infinity"
4444
or
4545
// 7.1.2 continued
4646
getOperator() = "-" and
4747
exists(Boolean sign |
4848
exprMayEqualInfinity(getLeftOperand(), sign) and
4949
exprMayEqualInfinity(getRightOperand(), sign)
5050
) and
51-
reason = "possible subtraction of an infinity from itself"
51+
reason = "from subtraction of an infinity from itself"
5252
or
5353
// 7.1.3: multiplication of zero by infinity
5454
getOperator() = "*" and
5555
exprMayEqualZero(getAnOperand()) and
5656
exprMayEqualInfinity(getAnOperand(), _) and
57-
reason = "possible multiplication of zero by infinity"
57+
reason = "from multiplication of zero by infinity"
5858
or
5959
// 7.1.4: Division of zero by zero, or infinity by infinity
6060
getOperator() = "/" and
6161
exprMayEqualZero(getLeftOperand()) and
6262
exprMayEqualZero(getRightOperand()) and
63-
reason = "possible division of zero by zero"
63+
reason = "from division of zero by zero"
6464
or
6565
// 7.1.4 continued
6666
getOperator() = "/" and
6767
exprMayEqualInfinity(getLeftOperand(), _) and
6868
exprMayEqualInfinity(getRightOperand(), _) and
69-
reason = "possible division of infinity by infinity"
69+
reason = "from division of infinity by infinity"
7070
or
7171
// 7.1.5: x % y where y is zero or x is infinite
7272
getOperator() = "%" and
7373
exprMayEqualInfinity(getLeftOperand(), _) and
74-
reason = "possible modulus of infinity"
74+
reason = "from modulus of infinity"
7575
or
7676
// 7.1.5 continued
7777
getOperator() = "%" and
7878
exprMayEqualZero(getRightOperand()) and
79-
reason = "possible modulus by zero"
79+
reason = "from modulus by zero"
8080
// 7.1.6 handles the sqrt function, not covered here.
8181
// 7.1.7 declares exceptions during invalid conversions, which we catch as sinks in our flow
8282
// analysis.
@@ -129,40 +129,66 @@ module InvalidNaNUsage implements DataFlow::ConfigSig {
129129

130130
predicate isSink(DataFlow::Node node) {
131131
not guardedNotFPClass(node.asExpr(), TNaN()) and
132-
(
132+
node instanceof InvalidNaNUsage
133+
}
134+
}
135+
136+
class InvalidNaNUsage extends DataFlow::Node {
137+
string description;
138+
string nanDescription;
139+
140+
InvalidNaNUsage() {
133141
// Case 1: NaNs shall not be compared, except to themselves
134142
exists(ComparisonOperation cmp |
135-
node.asExpr() = cmp.getAnOperand() and
136-
not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand())
143+
this.asExpr() = cmp.getAnOperand() and
144+
not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) and
145+
description = "Comparison involving a $@, which always evaluates to false." and
146+
nanDescription = "possibly NaN float value"
137147
)
138148
or
139149
// Case 2: NaNs and infinities shall not be cast to integers
140150
exists(Conversion c |
141-
node.asExpr() = c.getUnconverted() and
151+
this.asExpr() = c.getUnconverted() and
142152
c.getExpr().getType() instanceof FloatingPointType and
143-
c.getType() instanceof IntegralType
153+
c.getType() instanceof IntegralType and
154+
description = "$@ casted to integer." and
155+
nanDescription = "Possibly NaN float value"
144156
)
145157
//or
146158
//// Case 4: Functions shall not return NaNs or infinities
147159
//exists(ReturnStmt ret | node.asExpr() = ret.getExpr())
148-
)
149160
}
161+
162+
string getDescription() { result = description }
163+
164+
string getNaNDescription() { result = nanDescription }
150165
}
151166

152167
module InvalidNaNFlow = DataFlow::Global<InvalidNaNUsage>;
153168

154169
import InvalidNaNFlow::PathGraph
155170

156171
from
157-
Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink, string msg,
158-
string sourceString
172+
Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink,
173+
InvalidNaNUsage usage, Expr sourceExpr, string sourceString, Element extra, string extraString
159174
where
175+
not InvalidNaNFlow::PathGraph::edges(_, source, _, _) and
176+
not sourceExpr.isFromTemplateInstantiation(_) and
177+
not usage.asExpr().isFromTemplateInstantiation(_) and
160178
elem = MacroUnwrapper<Expr>::unwrapElement(sink.getNode().asExpr()) and
161-
not isExcluded(elem, FloatingTypes2Package::possibleMisuseOfUndetectedNaNQuery()) and
162-
(
163-
InvalidNaNFlow::flow(source.getNode(), sink.getNode()) and
164-
msg = "Invalid usage of possible $@." and
179+
usage = sink.getNode() and
180+
sourceExpr = source.getNode().asExpr() and
165181
sourceString =
166-
"NaN resulting from " + source.getNode().asExpr().(InvalidOperationExpr).getReason()
182+
" (" + source.getNode().asExpr().(InvalidOperationExpr).getReason() + ")" and
183+
InvalidNaNFlow::flow(source.getNode(), usage) and
184+
(
185+
if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction()
186+
then
187+
extraString = usage.getNaNDescription() + sourceString + " computed in function " + sourceExpr.getEnclosingFunction().getName()
188+
and extra = sourceExpr.getEnclosingFunction()
189+
else (
190+
extra = sourceExpr and
191+
extraString = usage.getNaNDescription() + sourceString
192+
)
167193
)
168-
select elem, source, sink, msg, source, sourceString
194+
select elem, source, sink, usage.getDescription(), extra, extraString

0 commit comments

Comments
 (0)