@@ -21,11 +21,13 @@ class InterestingBinaryOverflowingExpr extends BinaryArithmeticOperation {
21
21
or
22
22
exprMightOverflowPositively ( this )
23
23
) and
24
+ // Multiplication is not covered by the standard range analysis library, so implement our own
25
+ // mini analysis.
26
+ ( this instanceof MulExpr implies MulExprAnalysis:: overflows ( this ) ) and
27
+ // Not within a macro
24
28
not this .isAffectedByMacro ( ) and
25
29
// Ignore pointer arithmetic
26
30
not this instanceof PointerArithmeticOperation and
27
- // Covered by `IntMultToLong.ql` instead
28
- not this instanceof MulExpr and
29
31
// Not covered by this query - overflow/underflow in division is rare
30
32
not this instanceof DivExpr
31
33
}
@@ -138,6 +140,18 @@ class InterestingBinaryOverflowingExpr extends BinaryArithmeticOperation {
138
140
)
139
141
)
140
142
)
143
+ or
144
+ // The CERT rule for signed integer overflow has a very specific pattern it recommends
145
+ // for checking for multiplication underflow/overflow. We just use a heuristic here,
146
+ // which determines if at least 4 checks of the sort `a < INT_MAX / b` are present in the code.
147
+ this instanceof MulExpr and
148
+ count ( StrictRelationalOperation rel |
149
+ globalValueNumber ( rel .getAnOperand ( ) ) = i1 and
150
+ globalValueNumber ( rel .getAnOperand ( ) .( DivExpr ) .getRightOperand ( ) ) = i2
151
+ or
152
+ globalValueNumber ( rel .getAnOperand ( ) ) = i2 and
153
+ globalValueNumber ( rel .getAnOperand ( ) .( DivExpr ) .getRightOperand ( ) ) = i1
154
+ ) >= 4
141
155
)
142
156
}
143
157
@@ -193,3 +207,98 @@ class InterestingBinaryOverflowingExpr extends BinaryArithmeticOperation {
193
207
private class StrictRelationalOperation extends RelationalOperation {
194
208
StrictRelationalOperation ( ) { this .getOperator ( ) = [ ">" , "<" ] }
195
209
}
210
+
211
+ /**
212
+ * Module inspired by the IntMultToLong.ql query.
213
+ */
214
+ private module MulExprAnalysis {
215
+ /**
216
+ * As SimpleRangeAnalysis does not support reasoning about multiplication
217
+ * we create a tiny abstract interpreter for handling multiplication, which
218
+ * we invoke only after weeding out of all of trivial cases that we do
219
+ * not care about. By default, the maximum and minimum values are computed
220
+ * using SimpleRangeAnalysis.
221
+ */
222
+ class AnalyzableExpr extends Expr {
223
+ AnalyzableExpr ( ) {
224
+ // A integer multiplication, or an expression within an integral expression
225
+ this .( MulExpr ) .getType ( ) .getUnspecifiedType ( ) instanceof IntegralType or
226
+ this .getParent ( ) instanceof AnalyzableExpr or
227
+ this .( Conversion ) .getExpr ( ) instanceof AnalyzableExpr
228
+ }
229
+
230
+ float maxValue ( ) { result = upperBound ( this .getFullyConverted ( ) ) }
231
+
232
+ float minValue ( ) { result = lowerBound ( this .getFullyConverted ( ) ) }
233
+ }
234
+
235
+ class ParenAnalyzableExpr extends AnalyzableExpr , ParenthesisExpr {
236
+ override float maxValue ( ) { result = this .getExpr ( ) .( AnalyzableExpr ) .maxValue ( ) }
237
+
238
+ override float minValue ( ) { result = this .getExpr ( ) .( AnalyzableExpr ) .minValue ( ) }
239
+ }
240
+
241
+ class MulAnalyzableExpr extends AnalyzableExpr , MulExpr {
242
+ override float maxValue ( ) {
243
+ exists ( float x1 , float y1 , float x2 , float y2 |
244
+ x1 = this .getLeftOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .minValue ( ) and
245
+ x2 = this .getLeftOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .maxValue ( ) and
246
+ y1 = this .getRightOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .minValue ( ) and
247
+ y2 = this .getRightOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .maxValue ( ) and
248
+ result = ( x1 * y1 ) .maximum ( x1 * y2 ) .maximum ( x2 * y1 ) .maximum ( x2 * y2 )
249
+ )
250
+ }
251
+
252
+ override float minValue ( ) {
253
+ exists ( float x1 , float x2 , float y1 , float y2 |
254
+ x1 = this .getLeftOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .minValue ( ) and
255
+ x2 = this .getLeftOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .maxValue ( ) and
256
+ y1 = this .getRightOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .minValue ( ) and
257
+ y2 = this .getRightOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .maxValue ( ) and
258
+ result = ( x1 * y1 ) .minimum ( x1 * y2 ) .minimum ( x2 * y1 ) .minimum ( x2 * y2 )
259
+ )
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Analyze add expressions directly. This handles the case where an add expression is contributed to
265
+ * by a multiplication.
266
+ */
267
+ class AddAnalyzableExpr extends AnalyzableExpr , AddExpr {
268
+ override float maxValue ( ) {
269
+ result =
270
+ this .getLeftOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .maxValue ( ) +
271
+ this .getRightOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .maxValue ( )
272
+ }
273
+
274
+ override float minValue ( ) {
275
+ result =
276
+ this .getLeftOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .minValue ( ) +
277
+ this .getRightOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .minValue ( )
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Analyze sub expressions directly. This handles the case where a sub expression is contributed to
283
+ * by a multiplication.
284
+ */
285
+ class SubAnalyzableExpr extends AnalyzableExpr , SubExpr {
286
+ override float maxValue ( ) {
287
+ result =
288
+ this .getLeftOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .maxValue ( ) -
289
+ this .getRightOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .minValue ( )
290
+ }
291
+
292
+ override float minValue ( ) {
293
+ result =
294
+ this .getLeftOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .minValue ( ) -
295
+ this .getRightOperand ( ) .getFullyConverted ( ) .( AnalyzableExpr ) .maxValue ( )
296
+ }
297
+ }
298
+
299
+ predicate overflows ( MulExpr me ) {
300
+ me .( MulAnalyzableExpr ) .maxValue ( ) > exprMaxVal ( me )
301
+ or
302
+ me .( MulAnalyzableExpr ) .minValue ( ) < exprMinVal ( me )
303
+ }
304
+ }
0 commit comments