@@ -33,6 +33,8 @@ class InterestingOverflowingOperation extends Operation {
3333 // Multiplication is not covered by the standard range analysis library, so implement our own
3434 // mini analysis.
3535 ( this instanceof MulExpr implies MulExprAnalysis:: overflows ( this ) ) and
36+ // This shouldn't be a "safe" crement operation
37+ not LoopCounterAnalysis:: isCrementSafeFromOverflow ( this ) and
3638 // Not within a macro
3739 not this .isAffectedByMacro ( ) and
3840 // Ignore pointer arithmetic
@@ -328,3 +330,68 @@ private module MulExprAnalysis {
328330 me .( MulAnalyzableExpr ) .minValue ( ) < exprMinVal ( me )
329331 }
330332}
333+
334+ /**
335+ * An analysis on safe loop counters.
336+ */
337+ module LoopCounterAnalysis {
338+ newtype LoopBound =
339+ LoopUpperBound ( ) or
340+ LoopLowerBound ( )
341+
342+ predicate isLoopBounded (
343+ CrementOperation cop , ForStmt fs , Variable loopCounter , Expr initializer , Expr counterBound ,
344+ LoopBound boundKind , boolean equals
345+ ) {
346+ // Initialization sets the loop counter
347+ (
348+ loopCounter = fs .getInitialization ( ) .( DeclStmt ) .getADeclaration ( ) and
349+ initializer = loopCounter .getInitializer ( ) .getExpr ( )
350+ or
351+ loopCounter .getAnAssignment ( ) = initializer and
352+ initializer = fs .getInitialization ( ) .( ExprStmt ) .getExpr ( )
353+ ) and
354+ // Condition is a relation operation on the loop counter
355+ exists ( RelationalOperation relOp |
356+ fs .getCondition ( ) = relOp and
357+ ( if relOp .getOperator ( ) .charAt ( 1 ) = "=" then equals = true else equals = false )
358+ |
359+ relOp .getGreaterOperand ( ) = loopCounter .getAnAccess ( ) and
360+ relOp .getLesserOperand ( ) = counterBound and
361+ cop instanceof DecrementOperation and
362+ boundKind = LoopLowerBound ( )
363+ or
364+ relOp .getLesserOperand ( ) = loopCounter .getAnAccess ( ) and
365+ relOp .getGreaterOperand ( ) = counterBound and
366+ cop instanceof IncrementOperation and
367+ boundKind = LoopUpperBound ( )
368+ ) and
369+ // Update is a crement operation with the loop counter
370+ fs .getUpdate ( ) = cop and
371+ cop .getOperand ( ) = loopCounter .getAnAccess ( )
372+ }
373+
374+ /**
375+ * Holds if the crement operation is safe from under/overflow.
376+ */
377+ predicate isCrementSafeFromOverflow ( CrementOperation op ) {
378+ exists (
379+ Expr initializer , Expr counterBound , LoopBound boundKind , boolean equals , int equalsOffset
380+ |
381+ isLoopBounded ( op , _, _, initializer , counterBound , boundKind , equals ) and
382+ (
383+ equals = true and equalsOffset = 1
384+ or
385+ equals = false and equalsOffset = 0
386+ )
387+ |
388+ boundKind = LoopUpperBound ( ) and
389+ // upper bound of the inccrement is smaller than the maximum value representable in the type
390+ upperBound ( counterBound ) + equalsOffset <= typeUpperBound ( op .getType ( ) .getUnspecifiedType ( ) )
391+ or
392+ // the lower bound of the decrement is larger than the smal
393+ boundKind = LoopLowerBound ( ) and
394+ lowerBound ( counterBound ) - equalsOffset >= typeLowerBound ( op .getType ( ) .getUnspecifiedType ( ) )
395+ )
396+ }
397+ }
0 commit comments