@@ -33,6 +33,8 @@ class InterestingOverflowingOperation extends Operation {
33
33
// Multiplication is not covered by the standard range analysis library, so implement our own
34
34
// mini analysis.
35
35
( this instanceof MulExpr implies MulExprAnalysis:: overflows ( this ) ) and
36
+ // This shouldn't be a "safe" crement operation
37
+ not LoopCounterAnalysis:: isCrementSafeFromOverflow ( this ) and
36
38
// Not within a macro
37
39
not this .isAffectedByMacro ( ) and
38
40
// Ignore pointer arithmetic
@@ -328,3 +330,68 @@ private module MulExprAnalysis {
328
330
me .( MulAnalyzableExpr ) .minValue ( ) < exprMinVal ( me )
329
331
}
330
332
}
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