diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExpr.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExpr.qll index 46a5c735ca05..72b70ada4ed9 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExpr.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExpr.qll @@ -307,3 +307,8 @@ class SemConditionalExpr extends SemKnownExpr { branch = false and result = falseResult } } + +/** Holds if `upper = true` and `e <= bound` or `upper = false` and `e >= bound`. */ +predicate semHasConstantBoundConstantSpecific(SemExpr e, float bound, boolean upper) { + Specific::hasConstantBoundConstantSpecific(e, bound, upper) +} diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExprSpecific.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExprSpecific.qll index a92361ece17c..2ec277bf8cf9 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExprSpecific.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/SemanticExprSpecific.qll @@ -434,6 +434,50 @@ module SemanticExprConfig { /** Gets the expression associated with `instr`. */ SemExpr getSemanticExpr(IR::Instruction instr) { result = Equiv::getEquivalenceClass(instr) } + + private predicate typeBounds(SemType t, float lb, float ub) { + exists(SemIntegerType integralType, float limit | + integralType = t and limit = 2.pow(8 * integralType.getByteSize()) + | + if integralType instanceof SemBooleanType + then lb = 0 and ub = 1 + else + if integralType.isSigned() + then ( + lb = -(limit / 2) and ub = (limit / 2) - 1 + ) else ( + lb = 0 and ub = limit - 1 + ) + ) + or + // This covers all floating point types. The range is (-Inf, +Inf). + t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0 + } + + /** + * Holds if `upper = true` and `e <= bound` or `upper = false` and `e >= bound` based + * only on type information. + */ + predicate hasConstantBoundConstantSpecific(Expr e, float bound, boolean upper) { + exists( + SemType converted, SemType unconverted, float unconvertedLb, float convertedLb, + float unconvertedUb, float convertedUb + | + unconverted = getSemanticType(e.getUnconverted().getResultIRType()) and + converted = getSemanticType(e.getConverted().getResultIRType()) and + typeBounds(unconverted, unconvertedLb, unconvertedUb) and + typeBounds(converted, convertedLb, convertedUb) and + ( + upper = true and + unconvertedUb < convertedUb and + bound = unconvertedUb + or + upper = false and + unconvertedLb > convertedLb and + bound = unconvertedLb + ) + ) + } } predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1; @@ -457,3 +501,5 @@ IRBound::Bound getCppBound(SemBound bound) { bound = result } SemGuard getSemanticGuard(IRGuards::IRGuardCondition guard) { result = guard } IRGuards::IRGuardCondition getCppGuard(SemGuard guard) { guard = result } + +predicate hasConstantBoundConstantSpecific = SemanticExprConfig::hasConstantBoundConstantSpecific/3; diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisConstantSpecific.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisConstantSpecific.qll index d1e53530ef5a..54e46bfd00cb 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisConstantSpecific.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisConstantSpecific.qll @@ -74,7 +74,10 @@ module CppLangImplConstant implements LangSig { /** * Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`). */ - predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() } + predicate hasConstantBound(SemExpr e, float bound, boolean upper, SemReason reason) { + semHasConstantBoundConstantSpecific(e, bound, upper) and + reason instanceof SemTypeReason + } /** * Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`). diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisRelativeSpecific.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisRelativeSpecific.qll index 341fab173769..ba66793aae9b 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisRelativeSpecific.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisRelativeSpecific.qll @@ -110,7 +110,7 @@ module CppLangImplRelative implements LangSig { /** * Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`). */ - predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() } + predicate hasConstantBound(SemExpr e, float bound, boolean upper, SemReason reason) { none() } /** * Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`). diff --git a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisStage.qll index a6cacd8b4a79..3d0af5754d32 100644 --- a/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisStage.qll +++ b/cpp/ql/lib/semmle/code/cpp/rangeanalysis/new/internal/semantic/analysis/RangeAnalysisStage.qll @@ -155,7 +155,7 @@ signature module LangSig { /** * Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`). */ - predicate hasConstantBound(SemExpr e, D::Delta bound, boolean upper); + predicate hasConstantBound(SemExpr e, D::Delta bound, boolean upper, SemReason reason); /** * Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`). @@ -920,14 +920,15 @@ module RangeStage< * Holds if `e` has an upper (for `upper = true`) or lower * (for `upper = false`) bound of `b`. */ - private predicate baseBound(SemExpr e, D::Delta b, boolean upper) { - hasConstantBound(e, b, upper) + private predicate baseBound(SemExpr e, D::Delta b, boolean upper, SemReason reason) { + hasConstantBound(e, b, upper, reason) or upper = false and b = D::fromInt(0) and semPositive(e.(SemBitAndExpr).getAnOperand()) and // REVIEW: We let the language opt out here to preserve original results. - not ignoreZeroLowerBound(e) + not ignoreZeroLowerBound(e) and + reason instanceof SemNoReason } /** @@ -1055,11 +1056,10 @@ module RangeStage< origdelta = delta and reason instanceof SemNoReason or - baseBound(e, delta, upper) and + baseBound(e, delta, upper, reason) and b instanceof SemZeroBound and fromBackEdge = false and - origdelta = delta and - reason instanceof SemNoReason + origdelta = delta or exists(SemSsaVariable v, SemSsaReadPositionBlock bb | boundedSsa(v, bb, b, delta, upper, fromBackEdge, origdelta, reason) and diff --git a/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/RangeAnalysisUtil.qll b/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/RangeAnalysisUtil.qll index 12bb50321fa7..72e27d7804c9 100644 --- a/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/RangeAnalysisUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/security/InvalidPointerDereference/RangeAnalysisUtil.qll @@ -20,7 +20,8 @@ private Instruction getABoundIn(SemBound b, IRFunction func) { pragma[inline] private predicate boundedImpl(Instruction i, Instruction b, int delta) { exists(SemBound bound, IRFunction func | - semBounded(getSemanticExpr(i), bound, delta, true, _) and + semBounded(getSemanticExpr(i), bound, delta, true, + any(SemReason reason | not reason instanceof SemTypeReason)) and b = getABoundIn(bound, func) and i.getEnclosingIRFunction() = func ) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql index c38a012b27bf..5b0ab08bec22 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-193/ConstantSizeArrayOffByOne.ql @@ -28,7 +28,8 @@ Instruction getABoundIn(SemBound b, IRFunction func) { pragma[inline] predicate boundedImpl(Instruction i, Instruction b, int delta) { exists(SemBound bound, IRFunction func | - semBounded(getSemanticExpr(i), bound, delta, true, _) and + semBounded(getSemanticExpr(i), bound, delta, true, + any(SemReason reason | not reason instanceof SemTypeReason)) and b = getABoundIn(bound, func) and pragma[only_bind_out](i.getEnclosingIRFunction()) = func ) @@ -93,7 +94,8 @@ predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int size) { bindingset[pai] pragma[inline_late] predicate constantUpperBounded(PointerArithmeticInstruction pai, int delta) { - semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), delta, true, _) + semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), delta, true, + any(SemReason reason | not reason instanceof SemTypeReason)) } bindingset[pai, size] diff --git a/cpp/ql/test/library-tests/ir/range-analysis/SimpleRangeAnalysis_tests.cpp b/cpp/ql/test/library-tests/ir/range-analysis/SimpleRangeAnalysis_tests.cpp index df29578409b8..114d164a91a5 100644 --- a/cpp/ql/test/library-tests/ir/range-analysis/SimpleRangeAnalysis_tests.cpp +++ b/cpp/ql/test/library-tests/ir/range-analysis/SimpleRangeAnalysis_tests.cpp @@ -195,18 +195,18 @@ int test13(char c, int i) { int z = i+1; // $ overflow=+ range(z); // $ range="==InitializeParameter: i+1" range(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- MISSING: range=>=1 - range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- MISSING: range=>=1 + range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- range=<=4294967295 MISSING: range=>=1 return (double)(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- } // Regression test for ODASA-6013. int test14(int x) { int x0 = (int)(char)x; - range(x0); + range(x0); // $ range=<=127 range=>=-128 int x1 = (int)(unsigned char)x; - range(x1); + range(x1); // $ range=<=255 range=>=0 int x2 = (int)(unsigned short)x; - range(x2); + range(x2); // $ range=<=65535 range=>=0 int x3 = (int)(unsigned int)x; range(x3); char c0 = x; @@ -759,9 +759,9 @@ unsigned long mult_overflow() { unsigned long mult_lower_bound(unsigned int ui, unsigned long ul) { if (ui >= 10) { range(ui); // $ range=>=10 - range((unsigned long)ui); // $ range=>=10 - unsigned long result = (unsigned long)ui * ui; // $ overflow=+ - range(result); // $ MISSING: range=>=100 + range((unsigned long)ui); // $ range=>=10 range=<=4294967295 + unsigned long result = (unsigned long)ui * ui; // no overflow + range(result); // $ range=>=100 range=<=18446744065119617024 return result; // BUG: upper bound should be >= 18446744065119617025 } if (ul >= 10) { @@ -888,7 +888,7 @@ void notequal_variations(short n, float f) { } if (n >= 5) { - if (2 * n - 10 == 0) { // $ overflow=+ + if (2 * n - 10 == 0) { // no overflow range(n); // $ range=>=5 MISSING: range===5 return; } @@ -936,7 +936,7 @@ void two_bounds_from_one_test(short ss, unsigned short us) { range(ss); // -32768 .. 32767 } - if (ss + 1 < sizeof(int)) { // $ overflow=+ + if (ss + 1 < sizeof(int)) { // $ overflow=- range(ss); // -1 .. 2 } }