Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 574a1d8

Browse files
authored
Merge pull request #1037 from kevinbackhouse/RangeAnalysisAssignAddOverflow
Better overflow detection for AssignAdd/AssignSub
2 parents 23ce5bc + b7ac03d commit 574a1d8

5 files changed

Lines changed: 130 additions & 11 deletions

File tree

cpp/ql/src/semmle/code/cpp/rangeanalysis/SimpleRangeAnalysis.qll

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ predicate analyzableExpr(Expr e) {
106106
(e instanceof ConditionalExpr) or
107107
(e instanceof AddExpr) or
108108
(e instanceof SubExpr) or
109+
(e instanceof AssignExpr) or
110+
(e instanceof AssignAddExpr) or
111+
(e instanceof AssignSubExpr) or
109112
(e instanceof CrementOperation) or
110113
(e instanceof RemExpr) or
111114
(e instanceof CommaExpr) or
@@ -203,6 +206,18 @@ predicate exprDependsOnDef(
203206
| e = subExpr
204207
| exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar))
205208
or
209+
exists (AssignExpr addExpr
210+
| e = addExpr
211+
| exprDependsOnDef(addExpr.getRValue(), srcDef, srcVar))
212+
or
213+
exists (AssignAddExpr addExpr
214+
| e = addExpr
215+
| exprDependsOnDef(addExpr.getAnOperand(), srcDef, srcVar))
216+
or
217+
exists (AssignSubExpr subExpr
218+
| e = subExpr
219+
| exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar))
220+
or
206221
exists (CrementOperation crementExpr
207222
| e = crementExpr
208223
| exprDependsOnDef(crementExpr.getOperand(), srcDef, srcVar))
@@ -534,6 +549,22 @@ float getLowerBoundsImpl(Expr expr) {
534549
yHigh = getFullyConvertedUpperBounds(subExpr.getRightOperand()) and
535550
result = addRoundingDown(xLow, -yHigh))
536551
or
552+
exists (AssignExpr assign
553+
| expr = assign and
554+
result = getFullyConvertedLowerBounds(assign.getRValue()))
555+
or
556+
exists (AssignAddExpr addExpr, float xLow, float yLow
557+
| expr = addExpr and
558+
xLow = getFullyConvertedLowerBounds(addExpr.getLValue()) and
559+
yLow = getFullyConvertedLowerBounds(addExpr.getRValue()) and
560+
result = addRoundingDown(xLow, yLow))
561+
or
562+
exists (AssignSubExpr subExpr, float xLow, float yHigh
563+
| expr = subExpr and
564+
xLow = getFullyConvertedLowerBounds(subExpr.getLValue()) and
565+
yHigh = getFullyConvertedUpperBounds(subExpr.getRValue()) and
566+
result = addRoundingDown(xLow, -yHigh))
567+
or
537568
exists (PrefixIncrExpr incrExpr, float xLow
538569
| expr = incrExpr and
539570
xLow = getFullyConvertedLowerBounds(incrExpr.getOperand()) and
@@ -656,6 +687,22 @@ float getUpperBoundsImpl(Expr expr) {
656687
yLow = getFullyConvertedLowerBounds(subExpr.getRightOperand()) and
657688
result = addRoundingUp(xHigh, -yLow))
658689
or
690+
exists (AssignExpr assign
691+
| expr = assign and
692+
result = getFullyConvertedUpperBounds(assign.getRValue()))
693+
or
694+
exists (AssignAddExpr addExpr, float xHigh, float yHigh
695+
| expr = addExpr and
696+
xHigh = getFullyConvertedUpperBounds(addExpr.getLValue()) and
697+
yHigh = getFullyConvertedUpperBounds(addExpr.getRValue()) and
698+
result = addRoundingUp(xHigh, yHigh))
699+
or
700+
exists (AssignSubExpr subExpr, float xHigh, float yLow
701+
| expr = subExpr and
702+
xHigh = getFullyConvertedUpperBounds(subExpr.getLValue()) and
703+
yLow = getFullyConvertedLowerBounds(subExpr.getRValue()) and
704+
result = addRoundingUp(xHigh, -yLow))
705+
or
659706
exists (PrefixIncrExpr incrExpr, float xHigh
660707
| expr = incrExpr and
661708
xHigh = getFullyConvertedUpperBounds(incrExpr.getOperand()) and
@@ -1156,7 +1203,7 @@ private cached module SimpleRangeAnalysisCached {
11561203
// single minimum value.
11571204
result = min(float lb | lb = getTruncatedLowerBounds(expr) | lb)
11581205
}
1159-
1206+
11601207
/**
11611208
* Gets the upper bound of the expression.
11621209
*
@@ -1175,7 +1222,7 @@ private cached module SimpleRangeAnalysisCached {
11751222
// single maximum value.
11761223
result = max(float ub | ub = getTruncatedUpperBounds(expr) | ub)
11771224
}
1178-
1225+
11791226
/**
11801227
* Holds if `expr` has a provably empty range. For example:
11811228
*
@@ -1204,13 +1251,13 @@ private cached module SimpleRangeAnalysisCached {
12041251
predicate defMightOverflowNegatively(RangeSsaDefinition def, LocalScopeVariable v) {
12051252
getDefLowerBoundsImpl(def, v) < varMinVal(v)
12061253
}
1207-
1254+
12081255
/** Holds if the definition might overflow positively. */
12091256
cached
12101257
predicate defMightOverflowPositively(RangeSsaDefinition def, LocalScopeVariable v) {
12111258
getDefUpperBoundsImpl(def, v) > varMaxVal(v)
12121259
}
1213-
1260+
12141261
/**
12151262
* Holds if the definition might overflow (either positively or
12161263
* negatively).
@@ -1220,17 +1267,22 @@ private cached module SimpleRangeAnalysisCached {
12201267
defMightOverflowNegatively(def, v) or
12211268
defMightOverflowPositively(def, v)
12221269
}
1223-
1270+
12241271
/**
12251272
* Holds if the expression might overflow negatively. This predicate
12261273
* does not consider the possibility that the expression might overflow
12271274
* due to a conversion.
12281275
*/
12291276
cached
12301277
predicate exprMightOverflowNegatively(Expr expr) {
1231-
getLowerBoundsImpl(expr) < exprMinVal(expr)
1278+
getLowerBoundsImpl(expr) < exprMinVal(expr) or
1279+
1280+
// The lower bound of the expression `x--` is the same as the lower
1281+
// bound of `x`, so the standard logic (above) does not work for
1282+
// detecting whether it might overflow.
1283+
getLowerBoundsImpl(expr.(PostfixDecrExpr)) = exprMinVal(expr)
12321284
}
1233-
1285+
12341286
/**
12351287
* Holds if the expression might overflow negatively. Conversions
12361288
* are also taken into account. For example the expression
@@ -1242,17 +1294,22 @@ private cached module SimpleRangeAnalysisCached {
12421294
exprMightOverflowNegatively(expr) or
12431295
convertedExprMightOverflowNegatively(expr.getConversion())
12441296
}
1245-
1297+
12461298
/**
12471299
* Holds if the expression might overflow positively. This predicate
12481300
* does not consider the possibility that the expression might overflow
12491301
* due to a conversion.
12501302
*/
12511303
cached
12521304
predicate exprMightOverflowPositively(Expr expr) {
1253-
getUpperBoundsImpl(expr) > exprMaxVal(expr)
1305+
getUpperBoundsImpl(expr) > exprMaxVal(expr) or
1306+
1307+
// The upper bound of the expression `x++` is the same as the upper
1308+
// bound of `x`, so the standard logic (above) does not work for
1309+
// detecting whether it might overflow.
1310+
getUpperBoundsImpl(expr.(PostfixIncrExpr)) = exprMaxVal(expr)
12541311
}
1255-
1312+
12561313
/**
12571314
* Holds if the expression might overflow positively. Conversions
12581315
* are also taken into account. For example the expression
@@ -1264,7 +1321,7 @@ private cached module SimpleRangeAnalysisCached {
12641321
exprMightOverflowPositively(expr) or
12651322
convertedExprMightOverflowPositively(expr.getConversion())
12661323
}
1267-
1324+
12681325
/**
12691326
* Holds if the expression might overflow (either positively or
12701327
* negatively). The possibility that the expression might overflow

cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/lowerBound.expected

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,23 @@
423423
| test.c:398:22:398:22 | y | 5.0 |
424424
| test.c:399:10:399:11 | y1 | 1.0 |
425425
| test.c:399:15:399:16 | y2 | 5.0 |
426+
| test.c:407:3:407:3 | i | -2.147483648E9 |
427+
| test.c:408:7:408:7 | i | 10.0 |
428+
| test.c:410:3:410:3 | i | -2.147483648E9 |
429+
| test.c:411:3:411:3 | i | 10.0 |
430+
| test.c:412:7:412:7 | i | -2.147483648E9 |
431+
| test.c:414:3:414:3 | i | -2.147483648E9 |
432+
| test.c:415:3:415:3 | i | 40.0 |
433+
| test.c:416:7:416:7 | i | -2.147483648E9 |
434+
| test.c:418:3:418:3 | i | -2.147483648E9 |
435+
| test.c:418:7:418:7 | j | -2.147483648E9 |
436+
| test.c:419:7:419:7 | i | 40.0 |
437+
| test.c:421:3:421:3 | i | -2.147483648E9 |
438+
| test.c:421:8:421:8 | j | 40.0 |
439+
| test.c:422:7:422:7 | i | 50.0 |
440+
| test.c:424:3:424:3 | i | -2.147483648E9 |
441+
| test.c:424:13:424:13 | j | -2.147483648E9 |
442+
| test.c:425:7:425:7 | i | -2.147483648E9 |
426443
| test.cpp:10:7:10:7 | b | -2.147483648E9 |
427444
| test.cpp:11:5:11:5 | x | -2.147483648E9 |
428445
| test.cpp:13:10:13:10 | x | -2.147483648E9 |

cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/test.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,29 @@ unsigned int test_comma01(unsigned int x) {
398398
y2 = (y++, y += 3, y);
399399
return y1 + y2;
400400
}
401+
402+
void out(int i);
403+
404+
void test17() {
405+
int i, j;
406+
407+
i = 10;
408+
out(i); // 10
409+
410+
i = 10;
411+
i += 10;
412+
out(i); // 20
413+
414+
i = 40;
415+
i -= 10;
416+
out(i); // 30
417+
418+
i = j = 40;
419+
out(i); // 40
420+
421+
i = (j += 10);
422+
out(i); // 50
423+
424+
i = 20 + (j -= 10);
425+
out(i); // 60 [BUG: the analysis thinks it's 2^-31 .. 2^31-1]
426+
}

cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/upperBound.expected

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,23 @@
423423
| test.c:398:22:398:22 | y | 105.0 |
424424
| test.c:399:10:399:11 | y1 | 101.0 |
425425
| test.c:399:15:399:16 | y2 | 105.0 |
426+
| test.c:407:3:407:3 | i | 2.147483647E9 |
427+
| test.c:408:7:408:7 | i | 10.0 |
428+
| test.c:410:3:410:3 | i | 2.147483647E9 |
429+
| test.c:411:3:411:3 | i | 10.0 |
430+
| test.c:412:7:412:7 | i | 2.147483647E9 |
431+
| test.c:414:3:414:3 | i | 2.147483647E9 |
432+
| test.c:415:3:415:3 | i | 40.0 |
433+
| test.c:416:7:416:7 | i | 2.147483647E9 |
434+
| test.c:418:3:418:3 | i | 2.147483647E9 |
435+
| test.c:418:7:418:7 | j | 2.147483647E9 |
436+
| test.c:419:7:419:7 | i | 40.0 |
437+
| test.c:421:3:421:3 | i | 2.147483647E9 |
438+
| test.c:421:8:421:8 | j | 40.0 |
439+
| test.c:422:7:422:7 | i | 50.0 |
440+
| test.c:424:3:424:3 | i | 2.147483647E9 |
441+
| test.c:424:13:424:13 | j | 2.147483647E9 |
442+
| test.c:425:7:425:7 | i | 2.147483647E9 |
426443
| test.cpp:10:7:10:7 | b | 2.147483647E9 |
427444
| test.cpp:11:5:11:5 | x | 2.147483647E9 |
428445
| test.cpp:13:10:13:10 | x | 2.147483647E9 |

cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/IntegerOverflowTainted.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
| test3.c:13:16:13:19 | * ... | $@ flows to here and is used in an expression which might overflow negatively. | test3.c:11:15:11:18 | argv | User-provided value |
33
| test4.cpp:13:17:13:20 | access to array | $@ flows to here and is used in an expression which might overflow negatively. | test4.cpp:9:13:9:16 | argv | User-provided value |
44
| test5.cpp:10:9:10:15 | call to strtoul | $@ flows to here and is used in an expression which might overflow. | test5.cpp:9:7:9:9 | buf | User-provided value |
5+
| test.c:44:7:44:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:41:17:41:20 | argv | User-provided value |
6+
| test.c:54:7:54:12 | ... -- | $@ flows to here and is used in an expression which might overflow negatively. | test.c:51:17:51:20 | argv | User-provided value |

0 commit comments

Comments
 (0)