Skip to content

Commit e9750af

Browse files
authored
Merge pull request github#13783 from MathiasVP/type-bounds-for-new-range-analysis
C++: Constant type-bounds in the new range analysis
2 parents 37a5462 + 2d832db commit e9750af

File tree

8 files changed

+78
-21
lines changed

8 files changed

+78
-21
lines changed

cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExpr.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,8 @@ class SemConditionalExpr extends SemKnownExpr {
307307
branch = false and result = falseResult
308308
}
309309
}
310+
311+
/** Holds if `upper = true` and `e <= bound` or `upper = false` and `e >= bound`. */
312+
predicate semHasConstantBoundConstantSpecific(SemExpr e, float bound, boolean upper) {
313+
Specific::hasConstantBoundConstantSpecific(e, bound, upper)
314+
}

cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExprSpecific.qll

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,50 @@ module SemanticExprConfig {
434434

435435
/** Gets the expression associated with `instr`. */
436436
SemExpr getSemanticExpr(IR::Instruction instr) { result = Equiv::getEquivalenceClass(instr) }
437+
438+
private predicate typeBounds(SemType t, float lb, float ub) {
439+
exists(SemIntegerType integralType, float limit |
440+
integralType = t and limit = 2.pow(8 * integralType.getByteSize())
441+
|
442+
if integralType instanceof SemBooleanType
443+
then lb = 0 and ub = 1
444+
else
445+
if integralType.isSigned()
446+
then (
447+
lb = -(limit / 2) and ub = (limit / 2) - 1
448+
) else (
449+
lb = 0 and ub = limit - 1
450+
)
451+
)
452+
or
453+
// This covers all floating point types. The range is (-Inf, +Inf).
454+
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
455+
}
456+
457+
/**
458+
* Holds if `upper = true` and `e <= bound` or `upper = false` and `e >= bound` based
459+
* only on type information.
460+
*/
461+
predicate hasConstantBoundConstantSpecific(Expr e, float bound, boolean upper) {
462+
exists(
463+
SemType converted, SemType unconverted, float unconvertedLb, float convertedLb,
464+
float unconvertedUb, float convertedUb
465+
|
466+
unconverted = getSemanticType(e.getUnconverted().getResultIRType()) and
467+
converted = getSemanticType(e.getConverted().getResultIRType()) and
468+
typeBounds(unconverted, unconvertedLb, unconvertedUb) and
469+
typeBounds(converted, convertedLb, convertedUb) and
470+
(
471+
upper = true and
472+
unconvertedUb < convertedUb and
473+
bound = unconvertedUb
474+
or
475+
upper = false and
476+
unconvertedLb > convertedLb and
477+
bound = unconvertedLb
478+
)
479+
)
480+
}
437481
}
438482

439483
predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1;
@@ -457,3 +501,5 @@ IRBound::Bound getCppBound(SemBound bound) { bound = result }
457501
SemGuard getSemanticGuard(IRGuards::IRGuardCondition guard) { result = guard }
458502

459503
IRGuards::IRGuardCondition getCppGuard(SemGuard guard) { guard = result }
504+
505+
predicate hasConstantBoundConstantSpecific = SemanticExprConfig::hasConstantBoundConstantSpecific/3;

cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisConstantSpecific.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ module CppLangImplConstant implements LangSig<FloatDelta> {
7474
/**
7575
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
7676
*/
77-
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
77+
predicate hasConstantBound(SemExpr e, float bound, boolean upper, SemReason reason) {
78+
semHasConstantBoundConstantSpecific(e, bound, upper) and
79+
reason instanceof SemTypeReason
80+
}
7881

7982
/**
8083
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).

cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisRelativeSpecific.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ module CppLangImplRelative implements LangSig<FloatDelta> {
110110
/**
111111
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
112112
*/
113-
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
113+
predicate hasConstantBound(SemExpr e, float bound, boolean upper, SemReason reason) { none() }
114114

115115
/**
116116
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).

cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisStage.qll

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ signature module LangSig<DeltaSig D> {
155155
/**
156156
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
157157
*/
158-
predicate hasConstantBound(SemExpr e, D::Delta bound, boolean upper);
158+
predicate hasConstantBound(SemExpr e, D::Delta bound, boolean upper, SemReason reason);
159159

160160
/**
161161
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
@@ -920,14 +920,15 @@ module RangeStage<
920920
* Holds if `e` has an upper (for `upper = true`) or lower
921921
* (for `upper = false`) bound of `b`.
922922
*/
923-
private predicate baseBound(SemExpr e, D::Delta b, boolean upper) {
924-
hasConstantBound(e, b, upper)
923+
private predicate baseBound(SemExpr e, D::Delta b, boolean upper, SemReason reason) {
924+
hasConstantBound(e, b, upper, reason)
925925
or
926926
upper = false and
927927
b = D::fromInt(0) and
928928
semPositive(e.(SemBitAndExpr).getAnOperand()) and
929929
// REVIEW: We let the language opt out here to preserve original results.
930-
not ignoreZeroLowerBound(e)
930+
not ignoreZeroLowerBound(e) and
931+
reason instanceof SemNoReason
931932
}
932933

933934
/**
@@ -1055,11 +1056,10 @@ module RangeStage<
10551056
origdelta = delta and
10561057
reason instanceof SemNoReason
10571058
or
1058-
baseBound(e, delta, upper) and
1059+
baseBound(e, delta, upper, reason) and
10591060
b instanceof SemZeroBound and
10601061
fromBackEdge = false and
1061-
origdelta = delta and
1062-
reason instanceof SemNoReason
1062+
origdelta = delta
10631063
or
10641064
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
10651065
boundedSsa(v, bb, b, delta, upper, fromBackEdge, origdelta, reason) and

cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/RangeAnalysisUtil.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ private Instruction getABoundIn(SemBound b, IRFunction func) {
2020
pragma[inline]
2121
private predicate boundedImpl(Instruction i, Instruction b, int delta) {
2222
exists(SemBound bound, IRFunction func |
23-
semBounded(getSemanticExpr(i), bound, delta, true, _) and
23+
semBounded(getSemanticExpr(i), bound, delta, true,
24+
any(SemReason reason | not reason instanceof SemTypeReason)) and
2425
b = getABoundIn(bound, func) and
2526
i.getEnclosingIRFunction() = func
2627
)

cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ Instruction getABoundIn(SemBound b, IRFunction func) {
2828
pragma[inline]
2929
predicate boundedImpl(Instruction i, Instruction b, int delta) {
3030
exists(SemBound bound, IRFunction func |
31-
semBounded(getSemanticExpr(i), bound, delta, true, _) and
31+
semBounded(getSemanticExpr(i), bound, delta, true,
32+
any(SemReason reason | not reason instanceof SemTypeReason)) and
3233
b = getABoundIn(bound, func) and
3334
pragma[only_bind_out](i.getEnclosingIRFunction()) = func
3435
)
@@ -93,7 +94,8 @@ predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int size) {
9394
bindingset[pai]
9495
pragma[inline_late]
9596
predicate constantUpperBounded(PointerArithmeticInstruction pai, int delta) {
96-
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), delta, true, _)
97+
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), delta, true,
98+
any(SemReason reason | not reason instanceof SemTypeReason))
9799
}
98100

99101
bindingset[pai, size]

cpp/ql/test/library-tests/ir/range-analysis/SimpleRangeAnalysis_tests.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,18 +195,18 @@ int test13(char c, int i) {
195195
int z = i+1; // $ overflow=+
196196
range(z); // $ range="==InitializeParameter: i+1"
197197
range(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- MISSING: range=>=1
198-
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- MISSING: range=>=1
198+
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- range=<=4294967295 MISSING: range=>=1
199199
return (double)(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=-
200200
}
201201

202202
// Regression test for ODASA-6013.
203203
int test14(int x) {
204204
int x0 = (int)(char)x;
205-
range(x0);
205+
range(x0); // $ range=<=127 range=>=-128
206206
int x1 = (int)(unsigned char)x;
207-
range(x1);
207+
range(x1); // $ range=<=255 range=>=0
208208
int x2 = (int)(unsigned short)x;
209-
range(x2);
209+
range(x2); // $ range=<=65535 range=>=0
210210
int x3 = (int)(unsigned int)x;
211211
range(x3);
212212
char c0 = x;
@@ -759,9 +759,9 @@ unsigned long mult_overflow() {
759759
unsigned long mult_lower_bound(unsigned int ui, unsigned long ul) {
760760
if (ui >= 10) {
761761
range(ui); // $ range=>=10
762-
range((unsigned long)ui); // $ range=>=10
763-
unsigned long result = (unsigned long)ui * ui; // $ overflow=+
764-
range(result); // $ MISSING: range=>=100
762+
range((unsigned long)ui); // $ range=>=10 range=<=4294967295
763+
unsigned long result = (unsigned long)ui * ui; // no overflow
764+
range(result); // $ range=>=100 range=<=18446744065119617024
765765
return result; // BUG: upper bound should be >= 18446744065119617025
766766
}
767767
if (ul >= 10) {
@@ -888,7 +888,7 @@ void notequal_variations(short n, float f) {
888888
}
889889

890890
if (n >= 5) {
891-
if (2 * n - 10 == 0) { // $ overflow=+
891+
if (2 * n - 10 == 0) { // no overflow
892892
range(n); // $ range=>=5 MISSING: range===5
893893
return;
894894
}
@@ -936,7 +936,7 @@ void two_bounds_from_one_test(short ss, unsigned short us) {
936936
range(ss); // -32768 .. 32767
937937
}
938938

939-
if (ss + 1 < sizeof(int)) { // $ overflow=+
939+
if (ss + 1 < sizeof(int)) { // $ overflow=-
940940
range(ss); // -1 .. 2
941941
}
942942
}

0 commit comments

Comments
 (0)