@@ -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
152167module InvalidNaNFlow = DataFlow:: Global< InvalidNaNUsage > ;
153168
154169import InvalidNaNFlow:: PathGraph
155170
156171from
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
159174where
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