@@ -21,11 +21,13 @@ class InterestingBinaryOverflowingExpr extends BinaryArithmeticOperation {
2121 or
2222 exprMightOverflowPositively ( this )
2323 ) 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
2428 not this .isAffectedByMacro ( ) and
2529 // Ignore pointer arithmetic
2630 not this instanceof PointerArithmeticOperation and
27- // Covered by `IntMultToLong.ql` instead
28- not this instanceof MulExpr and
2931 // Not covered by this query - overflow/underflow in division is rare
3032 not this instanceof DivExpr
3133 }
@@ -138,6 +140,18 @@ class InterestingBinaryOverflowingExpr extends BinaryArithmeticOperation {
138140 )
139141 )
140142 )
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
141155 )
142156 }
143157
@@ -193,3 +207,98 @@ class InterestingBinaryOverflowingExpr extends BinaryArithmeticOperation {
193207private class StrictRelationalOperation extends RelationalOperation {
194208 StrictRelationalOperation ( ) { this .getOperator ( ) = [ ">" , "<" ] }
195209}
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