@@ -40,43 +40,43 @@ class InvalidOperationExpr extends BinaryOperation {
40
40
exprMayEqualInfinity ( getLeftOperand ( ) , sign ) and
41
41
exprMayEqualInfinity ( getRightOperand ( ) , sign .booleanNot ( ) )
42
42
) and
43
- reason = "possible addition of infinity and negative infinity"
43
+ reason = "from addition of infinity and negative infinity"
44
44
or
45
45
// 7.1.2 continued
46
46
getOperator ( ) = "-" and
47
47
exists ( Boolean sign |
48
48
exprMayEqualInfinity ( getLeftOperand ( ) , sign ) and
49
49
exprMayEqualInfinity ( getRightOperand ( ) , sign )
50
50
) and
51
- reason = "possible subtraction of an infinity from itself"
51
+ reason = "from subtraction of an infinity from itself"
52
52
or
53
53
// 7.1.3: multiplication of zero by infinity
54
54
getOperator ( ) = "*" and
55
55
exprMayEqualZero ( getAnOperand ( ) ) and
56
56
exprMayEqualInfinity ( getAnOperand ( ) , _) and
57
- reason = "possible multiplication of zero by infinity"
57
+ reason = "from multiplication of zero by infinity"
58
58
or
59
59
// 7.1.4: Division of zero by zero, or infinity by infinity
60
60
getOperator ( ) = "/" and
61
61
exprMayEqualZero ( getLeftOperand ( ) ) and
62
62
exprMayEqualZero ( getRightOperand ( ) ) and
63
- reason = "possible division of zero by zero"
63
+ reason = "from division of zero by zero"
64
64
or
65
65
// 7.1.4 continued
66
66
getOperator ( ) = "/" and
67
67
exprMayEqualInfinity ( getLeftOperand ( ) , _) and
68
68
exprMayEqualInfinity ( getRightOperand ( ) , _) and
69
- reason = "possible division of infinity by infinity"
69
+ reason = "from division of infinity by infinity"
70
70
or
71
71
// 7.1.5: x % y where y is zero or x is infinite
72
72
getOperator ( ) = "%" and
73
73
exprMayEqualInfinity ( getLeftOperand ( ) , _) and
74
- reason = "possible modulus of infinity"
74
+ reason = "from modulus of infinity"
75
75
or
76
76
// 7.1.5 continued
77
77
getOperator ( ) = "%" and
78
78
exprMayEqualZero ( getRightOperand ( ) ) and
79
- reason = "possible modulus by zero"
79
+ reason = "from modulus by zero"
80
80
// 7.1.6 handles the sqrt function, not covered here.
81
81
// 7.1.7 declares exceptions during invalid conversions, which we catch as sinks in our flow
82
82
// analysis.
@@ -129,40 +129,66 @@ module InvalidNaNUsage implements DataFlow::ConfigSig {
129
129
130
130
predicate isSink ( DataFlow:: Node node ) {
131
131
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 ( ) {
133
141
// Case 1: NaNs shall not be compared, except to themselves
134
142
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"
137
147
)
138
148
or
139
149
// Case 2: NaNs and infinities shall not be cast to integers
140
150
exists ( Conversion c |
141
- node .asExpr ( ) = c .getUnconverted ( ) and
151
+ this .asExpr ( ) = c .getUnconverted ( ) and
142
152
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"
144
156
)
145
157
//or
146
158
//// Case 4: Functions shall not return NaNs or infinities
147
159
//exists(ReturnStmt ret | node.asExpr() = ret.getExpr())
148
- )
149
160
}
161
+
162
+ string getDescription ( ) { result = description }
163
+
164
+ string getNaNDescription ( ) { result = nanDescription }
150
165
}
151
166
152
167
module InvalidNaNFlow = DataFlow:: Global< InvalidNaNUsage > ;
153
168
154
169
import InvalidNaNFlow:: PathGraph
155
170
156
171
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
159
174
where
175
+ not InvalidNaNFlow:: PathGraph:: edges ( _, source , _, _) and
176
+ not sourceExpr .isFromTemplateInstantiation ( _) and
177
+ not usage .asExpr ( ) .isFromTemplateInstantiation ( _) and
160
178
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
165
181
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
+ )
167
193
)
168
- select elem , source , sink , msg , source , sourceString
194
+ select elem , source , sink , usage . getDescription ( ) , extra , extraString
0 commit comments