Skip to content

Commit 7d2b40c

Browse files
authored
Merge pull request #21313 from MathiasVP/range-analysis-lower-bound-and-measure-enums
C++: Measure bounds for `Enum` constants and reduce `getBoundsLimit`
2 parents 149f3ed + 5ccd61a commit 7d2b40c

File tree

8 files changed

+661
-4
lines changed

8 files changed

+661
-4
lines changed

cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeAnalysisUtils.qll

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ predicate cmpWithLinearBound(
404404
* For example, if `t` is a signed 32-bit type then holds if `lb` is
405405
* `-2^31` and `ub` is `2^31 - 1`.
406406
*/
407-
private predicate typeBounds(ArithmeticType t, float lb, float ub) {
407+
private predicate typeBounds0(ArithmeticType t, float lb, float ub) {
408408
exists(IntegralType integralType, float limit |
409409
integralType = t and limit = 2.pow(8 * integralType.getSize())
410410
|
@@ -423,6 +423,42 @@ private predicate typeBounds(ArithmeticType t, float lb, float ub) {
423423
t instanceof FloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
424424
}
425425

426+
/**
427+
* Gets the underlying type for an enumeration `e`.
428+
*
429+
* If the enumeration does not have an explicit type we approximate it using
430+
* the following rules:
431+
* - The result type is always `signed`, and
432+
* - if the largest value fits in an `int` the result is `int`. Otherwise, the
433+
* result is `long`.
434+
*/
435+
private IntegralType getUnderlyingTypeForEnum(Enum e) {
436+
result = e.getExplicitUnderlyingType()
437+
or
438+
not e.hasExplicitUnderlyingType() and
439+
result.isSigned() and
440+
exists(IntType intType |
441+
if max(e.getAnEnumConstant().getValue().toFloat()) >= 2.pow(8 * intType.getSize() - 1)
442+
then result instanceof LongType
443+
else result = intType
444+
)
445+
}
446+
447+
/**
448+
* Holds if `lb` and `ub` are the lower and upper bounds of the unspecified
449+
* type `t`.
450+
*
451+
* For example, if `t` is a signed 32-bit type then holds if `lb` is
452+
* `-2^31` and `ub` is `2^31 - 1`.
453+
*
454+
* Unlike `typeBounds0`, this predicate also handles `Enum` types.
455+
*/
456+
private predicate typeBounds(Type t, float lb, float ub) {
457+
typeBounds0(t, lb, ub)
458+
or
459+
typeBounds0(getUnderlyingTypeForEnum(t), lb, ub)
460+
}
461+
426462
private Type stripReference(Type t) {
427463
if t instanceof ReferenceType then result = t.(ReferenceType).getBaseType() else result = t
428464
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,8 @@ private module BoundsEstimate {
512512
*/
513513
float getBoundsLimit() {
514514
// This limit is arbitrary, but low enough that it prevents timeouts on
515-
// specific observed customer databases (and the in the tests).
516-
result = 2.0.pow(40)
515+
// specific observed customer databases (and in the tests).
516+
result = 2.0.pow(29)
517517
}
518518

519519
/** Gets the maximum number of bounds possible for `t` when widening is used. */

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

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,7 @@
10251025
| test.c:970:12:970:12 | y | 256 |
10261026
| test.c:971:9:971:9 | x | 2147483647 |
10271027
| test.c:972:9:972:9 | y | 256 |
1028+
| test.c:985:7:985:7 | e | -2147483648 |
10281029
| test.cpp:10:7:10:7 | b | -2147483648 |
10291030
| test.cpp:11:5:11:5 | x | -2147483648 |
10301031
| test.cpp:13:10:13:10 | x | -2147483648 |
@@ -1093,3 +1094,64 @@
10931094
| test.cpp:122:4:122:4 | n | 0 |
10941095
| test.cpp:122:8:122:8 | n | 0 |
10951096
| test.cpp:122:12:122:12 | n | 1 |
1097+
| test_nr_of_bounds.cpp:40:5:40:20 | x | 0 |
1098+
| test_nr_of_bounds.cpp:40:5:40:20 | x | 0 |
1099+
| test_nr_of_bounds.cpp:41:5:41:20 | x | 0 |
1100+
| test_nr_of_bounds.cpp:41:5:41:20 | x | 0 |
1101+
| test_nr_of_bounds.cpp:42:5:42:20 | x | 0 |
1102+
| test_nr_of_bounds.cpp:42:5:42:20 | x | 0 |
1103+
| test_nr_of_bounds.cpp:43:5:43:20 | x | 0 |
1104+
| test_nr_of_bounds.cpp:43:5:43:20 | x | 0 |
1105+
| test_nr_of_bounds.cpp:44:5:44:20 | x | 0 |
1106+
| test_nr_of_bounds.cpp:44:5:44:20 | x | 0 |
1107+
| test_nr_of_bounds.cpp:45:5:45:20 | x | 0 |
1108+
| test_nr_of_bounds.cpp:45:5:45:20 | x | 0 |
1109+
| test_nr_of_bounds.cpp:46:5:46:20 | x | 0 |
1110+
| test_nr_of_bounds.cpp:46:5:46:20 | x | 0 |
1111+
| test_nr_of_bounds.cpp:47:5:47:20 | x | 0 |
1112+
| test_nr_of_bounds.cpp:47:5:47:20 | x | 0 |
1113+
| test_nr_of_bounds.cpp:48:5:48:20 | x | 0 |
1114+
| test_nr_of_bounds.cpp:48:5:48:20 | x | 0 |
1115+
| test_nr_of_bounds.cpp:49:5:49:20 | x | 0 |
1116+
| test_nr_of_bounds.cpp:49:5:49:20 | x | 0 |
1117+
| test_nr_of_bounds.cpp:50:5:50:20 | x | 0 |
1118+
| test_nr_of_bounds.cpp:50:5:50:20 | x | 0 |
1119+
| test_nr_of_bounds.cpp:51:5:51:20 | x | 0 |
1120+
| test_nr_of_bounds.cpp:51:5:51:20 | x | 0 |
1121+
| test_nr_of_bounds.cpp:52:5:52:20 | x | 0 |
1122+
| test_nr_of_bounds.cpp:52:5:52:20 | x | 0 |
1123+
| test_nr_of_bounds.cpp:53:5:53:20 | x | 0 |
1124+
| test_nr_of_bounds.cpp:53:5:53:20 | x | 0 |
1125+
| test_nr_of_bounds.cpp:54:5:54:20 | x | 0 |
1126+
| test_nr_of_bounds.cpp:54:5:54:20 | x | 0 |
1127+
| test_nr_of_bounds.cpp:55:5:55:20 | x | 0 |
1128+
| test_nr_of_bounds.cpp:55:5:55:20 | x | 0 |
1129+
| test_nr_of_bounds.cpp:56:5:56:20 | x | 0 |
1130+
| test_nr_of_bounds.cpp:56:5:56:20 | x | 0 |
1131+
| test_nr_of_bounds.cpp:57:5:57:20 | x | 0 |
1132+
| test_nr_of_bounds.cpp:57:5:57:20 | x | 0 |
1133+
| test_nr_of_bounds.cpp:58:5:58:20 | x | 0 |
1134+
| test_nr_of_bounds.cpp:58:5:58:20 | x | 0 |
1135+
| test_nr_of_bounds.cpp:59:5:59:20 | x | 0 |
1136+
| test_nr_of_bounds.cpp:59:5:59:20 | x | 0 |
1137+
| test_nr_of_bounds.cpp:60:5:60:20 | x | 0 |
1138+
| test_nr_of_bounds.cpp:60:5:60:20 | x | 0 |
1139+
| test_nr_of_bounds.cpp:61:5:61:20 | x | 0 |
1140+
| test_nr_of_bounds.cpp:61:5:61:20 | x | 0 |
1141+
| test_nr_of_bounds.cpp:62:5:62:20 | x | 0 |
1142+
| test_nr_of_bounds.cpp:62:5:62:20 | x | 0 |
1143+
| test_nr_of_bounds.cpp:63:5:63:20 | x | 0 |
1144+
| test_nr_of_bounds.cpp:63:5:63:20 | x | 0 |
1145+
| test_nr_of_bounds.cpp:64:5:64:20 | x | 0 |
1146+
| test_nr_of_bounds.cpp:64:5:64:20 | x | 0 |
1147+
| test_nr_of_bounds.cpp:65:5:65:21 | x | 0 |
1148+
| test_nr_of_bounds.cpp:65:5:65:21 | x | 0 |
1149+
| test_nr_of_bounds.cpp:66:5:66:21 | x | 0 |
1150+
| test_nr_of_bounds.cpp:66:5:66:21 | x | 0 |
1151+
| test_nr_of_bounds.cpp:67:5:67:21 | x | 0 |
1152+
| test_nr_of_bounds.cpp:67:5:67:21 | x | 0 |
1153+
| test_nr_of_bounds.cpp:68:5:68:21 | x | 0 |
1154+
| test_nr_of_bounds.cpp:68:5:68:21 | x | 0 |
1155+
| test_nr_of_bounds.cpp:69:5:69:21 | x | 0 |
1156+
| test_nr_of_bounds.cpp:69:5:69:21 | x | 0 |
1157+
| test_nr_of_bounds.cpp:72:12:72:12 | x | 0 |

0 commit comments

Comments
 (0)