Merge branch 'main' into rdmarsh2/range-analysis-overflow

This commit is contained in:
Robert Marsh
2023-04-05 16:19:55 -04:00
287 changed files with 33913 additions and 6545 deletions

View File

@@ -1,86 +1 @@
import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.ValueNumbering
private newtype TBound =
TBoundZero() or
TBoundValueNumber(ValueNumber vn) {
exists(Instruction i |
vn.getAnInstruction() = i and
(
i.getResultIRType() instanceof IRIntegerType or
i.getResultIRType() instanceof IRAddressType
) and
not vn.getAnInstruction() instanceof ConstantInstruction
|
i instanceof PhiInstruction
or
i instanceof InitializeParameterInstruction
or
i instanceof CallInstruction
or
i instanceof VariableAddressInstruction
or
i instanceof FieldAddressInstruction
or
i.(LoadInstruction).getSourceAddress() instanceof VariableAddressInstruction
or
i.(LoadInstruction).getSourceAddress() instanceof FieldAddressInstruction
or
i.getAUse() instanceof ArgumentOperand
or
i instanceof PointerArithmeticInstruction
or
i.getAUse() instanceof AddressOperand
)
}
/**
* A bound that may be inferred for an expression plus/minus an integer delta.
*/
abstract class Bound extends TBound {
abstract string toString();
/** Gets an expression that equals this bound plus `delta`. */
abstract Instruction getInstruction(int delta);
/** Gets an expression that equals this bound. */
Instruction getInstruction() { result = getInstruction(0) }
abstract Location getLocation();
}
/**
* The bound that corresponds to the integer 0. This is used to represent all
* integer bounds as bounds are always accompanied by an added integer delta.
*/
class ZeroBound extends Bound, TBoundZero {
override string toString() { result = "0" }
override Instruction getInstruction(int delta) {
result.(ConstantValueInstruction).getValue().toInt() = delta
}
override Location getLocation() { result instanceof UnknownDefaultLocation }
}
/**
* A bound corresponding to the value of an `Instruction`.
*/
class ValueNumberBound extends Bound, TBoundValueNumber {
ValueNumber vn;
ValueNumberBound() { this = TBoundValueNumber(vn) }
/** Gets an `Instruction` that equals this bound. */
override Instruction getInstruction(int delta) {
this = TBoundValueNumber(valueNumber(result)) and delta = 0
}
override string toString() { result = "ValueNumberBound" }
override Location getLocation() { result = vn.getLocation() }
/** Gets the value number that equals this bound. */
ValueNumber getValueNumber() { result = vn }
}
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Bound

View File

@@ -0,0 +1,115 @@
/**
* This module implements subclasses for various DataFlow nodes that extends
* their `toString()` predicates with range information, if applicable. By
* including this module in a `path-problem` query, this range information
* will be displayed at each step in the query results.
*
* This is currently implemented for `DataFlow::ExprNode` and `DataFlow::DefinitionByReferenceNode`,
* but it is not yet implemented for `DataFlow::ParameterNode`.
*/
private import cpp
private import semmle.code.cpp.dataflow.DataFlow
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
string getExprBoundAsString(Expr e) {
if exists(lowerBound(e)) and exists(upperBound(e))
then result = "[" + lowerBound(e) + ", " + upperBound(e) + "]"
else result = "[unknown range]"
}
/**
* Holds for any integer type after resolving typedefs and stripping `const`
* specifiers, such as for `const size_t`
*/
predicate isIntegralType(Type t) {
// We use `getUnspecifiedType` here because without it things like
// `const size_t` aren't considered to be integral
t.getUnspecifiedType() instanceof IntegralType
}
/**
* Holds for any reference to an integer type after resolving typedefs and
* stripping `const` specifiers, such as for `const size_t&`
*/
predicate isIntegralReferenceType(Type t) { isIntegralType(t.(ReferenceType).stripType()) }
/**
* Holds for any pointer to an integer type after resolving typedefs and
* stripping `const` specifiers, such as for `const size_t*`. This predicate
* holds for any pointer depth, such as for `const size_t**`.
*/
predicate isIntegralPointerType(Type t) { isIntegralType(t.(PointerType).stripType()) }
predicate hasIntegralOrReferenceIntegralType(Locatable e) {
exists(Type t |
(
t = e.(Expr).getUnspecifiedType()
or
// This will cover variables, parameters, type declarations, etc.
t = e.(DeclarationEntry).getUnspecifiedType()
) and
(isIntegralType(t) or isIntegralReferenceType(t))
)
}
Expr getLOp(Operation o) {
result = o.(BinaryOperation).getLeftOperand() or
result = o.(Assignment).getLValue()
}
Expr getROp(Operation o) {
result = o.(BinaryOperation).getRightOperand() or
result = o.(Assignment).getRValue()
}
/**
* Display the ranges of expressions in the path view
*/
private class ExprRangeNode extends DataFlow::ExprNode {
pragma[inline]
private string getIntegralBounds(Expr arg) {
if hasIntegralOrReferenceIntegralType(arg)
then result = getExprBoundAsString(arg)
else result = ""
}
private string getOperationBounds(Operation e) {
result =
getExprBoundAsString(e) + " = " + getExprBoundAsString(getLOp(e)) + e.getOperator() +
getExprBoundAsString(getROp(e))
}
private string getCallBounds(Call e) {
result =
getExprBoundAsString(e) + "(" +
concat(Expr arg, int i | arg = e.getArgument(i) | getIntegralBounds(arg) order by i, ",") +
")"
}
override string toString() {
exists(Expr e | e = getExpr() |
if hasIntegralOrReferenceIntegralType(e)
then
result = super.toString() + ": " + getOperationBounds(e)
or
result = super.toString() + ": " + getCallBounds(e)
or
not exists(getOperationBounds(e)) and
not exists(getCallBounds(e)) and
result = super.toString() + ": " + getExprBoundAsString(e)
else result = super.toString()
)
}
}
/**
* Display the ranges of expressions in the path view
*/
private class ReferenceArgumentRangeNode extends DataFlow::DefinitionByReferenceNode {
override string toString() {
if hasIntegralOrReferenceIntegralType(asDefiningArgument())
then result = super.toString() + ": " + getExprBoundAsString(getArgument())
else result = super.toString()
}
}

View File

@@ -1,3 +0,0 @@
import experimental.semmle.code.cpp.semantic.SemanticBound
private import RangeAnalysisImpl as Impl
import Impl::Public

View File

@@ -192,7 +192,8 @@ class ClassAggregateLiteral extends AggregateLiteral {
*/
Expr getFieldExpr(Field field) {
field = classType.getAField() and
aggregate_field_init(underlyingElement(this), unresolveElement(result), unresolveElement(field))
aggregate_field_init(underlyingElement(this), unresolveElement(result), unresolveElement(field),
_)
}
/**
@@ -264,7 +265,7 @@ class ArrayOrVectorAggregateLiteral extends AggregateLiteral {
* element `elementIndex`, if present.
*/
Expr getElementExpr(int elementIndex) {
aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex)
aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex, _)
}
/**

View File

@@ -159,26 +159,56 @@ private predicate fieldAddressValueNumber(
tvalueNumber(instr.getObjectAddress()) = objectAddress
}
pragma[nomagic]
private predicate binaryValueNumber0(
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, boolean isLeft,
TValueNumber valueNumber
) {
not instr instanceof PointerArithmeticInstruction and
instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and
(
isLeft = true and
tvalueNumber(instr.getLeft()) = valueNumber
or
isLeft = false and
tvalueNumber(instr.getRight()) = valueNumber
)
}
pragma[assume_small_delta]
private predicate binaryValueNumber(
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
TValueNumber rightOperand
) {
instr.getEnclosingIRFunction() = irFunc and
not instr instanceof PointerArithmeticInstruction and
instr.getOpcode() = opcode and
tvalueNumber(instr.getLeft()) = leftOperand and
tvalueNumber(instr.getRight()) = rightOperand
binaryValueNumber0(instr, irFunc, opcode, true, leftOperand) and
binaryValueNumber0(instr, irFunc, opcode, false, rightOperand)
}
private predicate pointerArithmeticValueNumber(
pragma[nomagic]
private predicate pointerArithmeticValueNumber0(
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
TValueNumber leftOperand, TValueNumber rightOperand
boolean isLeft, TValueNumber valueNumber
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and
instr.getElementSize() = elementSize and
tvalueNumber(instr.getLeft()) = leftOperand and
tvalueNumber(instr.getRight()) = rightOperand
(
isLeft = true and
tvalueNumber(instr.getLeft()) = valueNumber
or
isLeft = false and
tvalueNumber(instr.getRight()) = valueNumber
)
}
pragma[assume_small_delta]
private predicate pointerArithmeticValueNumber(
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
TValueNumber leftOperand, TValueNumber rightOperand
) {
pointerArithmeticValueNumber0(instr, irFunc, opcode, elementSize, true, leftOperand) and
pointerArithmeticValueNumber0(instr, irFunc, opcode, elementSize, false, rightOperand)
}
private predicate unaryValueNumber(
@@ -203,14 +233,29 @@ private predicate inheritanceConversionValueNumber(
unique( | | instr.getDerivedClass()) = derivedClass
}
pragma[nomagic]
private predicate loadTotalOverlapValueNumber0(
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
boolean isAddress
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getResultIRType() = type and
(
isAddress = true and
tvalueNumberOfOperand(instr.getSourceAddressOperand()) = valueNumber
or
isAddress = false and
tvalueNumber(instr.getSourceValueOperand().getAnyDef()) = valueNumber
)
}
pragma[assume_small_delta]
private predicate loadTotalOverlapValueNumber(
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand,
TValueNumber operand
) {
instr.getEnclosingIRFunction() = irFunc and
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand and
instr.getResultIRType() = type
loadTotalOverlapValueNumber0(instr, irFunc, type, operand, true) and
loadTotalOverlapValueNumber0(instr, irFunc, type, memOperand, false)
}
/**

View File

@@ -159,26 +159,56 @@ private predicate fieldAddressValueNumber(
tvalueNumber(instr.getObjectAddress()) = objectAddress
}
pragma[nomagic]
private predicate binaryValueNumber0(
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, boolean isLeft,
TValueNumber valueNumber
) {
not instr instanceof PointerArithmeticInstruction and
instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and
(
isLeft = true and
tvalueNumber(instr.getLeft()) = valueNumber
or
isLeft = false and
tvalueNumber(instr.getRight()) = valueNumber
)
}
pragma[assume_small_delta]
private predicate binaryValueNumber(
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
TValueNumber rightOperand
) {
instr.getEnclosingIRFunction() = irFunc and
not instr instanceof PointerArithmeticInstruction and
instr.getOpcode() = opcode and
tvalueNumber(instr.getLeft()) = leftOperand and
tvalueNumber(instr.getRight()) = rightOperand
binaryValueNumber0(instr, irFunc, opcode, true, leftOperand) and
binaryValueNumber0(instr, irFunc, opcode, false, rightOperand)
}
private predicate pointerArithmeticValueNumber(
pragma[nomagic]
private predicate pointerArithmeticValueNumber0(
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
TValueNumber leftOperand, TValueNumber rightOperand
boolean isLeft, TValueNumber valueNumber
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and
instr.getElementSize() = elementSize and
tvalueNumber(instr.getLeft()) = leftOperand and
tvalueNumber(instr.getRight()) = rightOperand
(
isLeft = true and
tvalueNumber(instr.getLeft()) = valueNumber
or
isLeft = false and
tvalueNumber(instr.getRight()) = valueNumber
)
}
pragma[assume_small_delta]
private predicate pointerArithmeticValueNumber(
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
TValueNumber leftOperand, TValueNumber rightOperand
) {
pointerArithmeticValueNumber0(instr, irFunc, opcode, elementSize, true, leftOperand) and
pointerArithmeticValueNumber0(instr, irFunc, opcode, elementSize, false, rightOperand)
}
private predicate unaryValueNumber(
@@ -203,14 +233,29 @@ private predicate inheritanceConversionValueNumber(
unique( | | instr.getDerivedClass()) = derivedClass
}
pragma[nomagic]
private predicate loadTotalOverlapValueNumber0(
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
boolean isAddress
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getResultIRType() = type and
(
isAddress = true and
tvalueNumberOfOperand(instr.getSourceAddressOperand()) = valueNumber
or
isAddress = false and
tvalueNumber(instr.getSourceValueOperand().getAnyDef()) = valueNumber
)
}
pragma[assume_small_delta]
private predicate loadTotalOverlapValueNumber(
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand,
TValueNumber operand
) {
instr.getEnclosingIRFunction() = irFunc and
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand and
instr.getResultIRType() = type
loadTotalOverlapValueNumber0(instr, irFunc, type, operand, true) and
loadTotalOverlapValueNumber0(instr, irFunc, type, memOperand, false)
}
/**

View File

@@ -159,26 +159,56 @@ private predicate fieldAddressValueNumber(
tvalueNumber(instr.getObjectAddress()) = objectAddress
}
pragma[nomagic]
private predicate binaryValueNumber0(
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, boolean isLeft,
TValueNumber valueNumber
) {
not instr instanceof PointerArithmeticInstruction and
instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and
(
isLeft = true and
tvalueNumber(instr.getLeft()) = valueNumber
or
isLeft = false and
tvalueNumber(instr.getRight()) = valueNumber
)
}
pragma[assume_small_delta]
private predicate binaryValueNumber(
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
TValueNumber rightOperand
) {
instr.getEnclosingIRFunction() = irFunc and
not instr instanceof PointerArithmeticInstruction and
instr.getOpcode() = opcode and
tvalueNumber(instr.getLeft()) = leftOperand and
tvalueNumber(instr.getRight()) = rightOperand
binaryValueNumber0(instr, irFunc, opcode, true, leftOperand) and
binaryValueNumber0(instr, irFunc, opcode, false, rightOperand)
}
private predicate pointerArithmeticValueNumber(
pragma[nomagic]
private predicate pointerArithmeticValueNumber0(
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
TValueNumber leftOperand, TValueNumber rightOperand
boolean isLeft, TValueNumber valueNumber
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getOpcode() = opcode and
instr.getElementSize() = elementSize and
tvalueNumber(instr.getLeft()) = leftOperand and
tvalueNumber(instr.getRight()) = rightOperand
(
isLeft = true and
tvalueNumber(instr.getLeft()) = valueNumber
or
isLeft = false and
tvalueNumber(instr.getRight()) = valueNumber
)
}
pragma[assume_small_delta]
private predicate pointerArithmeticValueNumber(
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
TValueNumber leftOperand, TValueNumber rightOperand
) {
pointerArithmeticValueNumber0(instr, irFunc, opcode, elementSize, true, leftOperand) and
pointerArithmeticValueNumber0(instr, irFunc, opcode, elementSize, false, rightOperand)
}
private predicate unaryValueNumber(
@@ -203,14 +233,29 @@ private predicate inheritanceConversionValueNumber(
unique( | | instr.getDerivedClass()) = derivedClass
}
pragma[nomagic]
private predicate loadTotalOverlapValueNumber0(
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
boolean isAddress
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getResultIRType() = type and
(
isAddress = true and
tvalueNumberOfOperand(instr.getSourceAddressOperand()) = valueNumber
or
isAddress = false and
tvalueNumber(instr.getSourceValueOperand().getAnyDef()) = valueNumber
)
}
pragma[assume_small_delta]
private predicate loadTotalOverlapValueNumber(
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand,
TValueNumber operand
) {
instr.getEnclosingIRFunction() = irFunc and
tvalueNumber(instr.getAnOperand().(MemoryOperand).getAnyDef()) = memOperand and
tvalueNumberOfOperand(instr.getAnOperand().(AddressOperand)) = operand and
instr.getResultIRType() = type
loadTotalOverlapValueNumber0(instr, irFunc, type, operand, true) and
loadTotalOverlapValueNumber0(instr, irFunc, type, memOperand, false)
}
/**

View File

@@ -5,11 +5,11 @@
private import cpp
private import semmle.code.cpp.ir.IR
private import experimental.semmle.code.cpp.semantic.SemanticBound
private import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
private import RangeAnalysisImpl
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
/**
* Gets the lower bound of the expression.
*

View File

@@ -5,7 +5,7 @@
private import cpp as Cpp
private import semmle.code.cpp.ir.IR as IR
private import Semantic
private import experimental.semmle.code.cpp.rangeanalysis.Bound as IRBound
private import analysis.Bound as IRBound
private import semmle.code.cpp.controlflow.IRGuards as IRGuards
private import semmle.code.cpp.ir.ValueNumbering

View File

@@ -0,0 +1,86 @@
import cpp
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.ValueNumbering
private newtype TBound =
TBoundZero() or
TBoundValueNumber(ValueNumber vn) {
exists(Instruction i |
vn.getAnInstruction() = i and
(
i.getResultIRType() instanceof IRIntegerType or
i.getResultIRType() instanceof IRAddressType
) and
not vn.getAnInstruction() instanceof ConstantInstruction
|
i instanceof PhiInstruction
or
i instanceof InitializeParameterInstruction
or
i instanceof CallInstruction
or
i instanceof VariableAddressInstruction
or
i instanceof FieldAddressInstruction
or
i.(LoadInstruction).getSourceAddress() instanceof VariableAddressInstruction
or
i.(LoadInstruction).getSourceAddress() instanceof FieldAddressInstruction
or
i.getAUse() instanceof ArgumentOperand
or
i instanceof PointerArithmeticInstruction
or
i.getAUse() instanceof AddressOperand
)
}
/**
* A bound that may be inferred for an expression plus/minus an integer delta.
*/
abstract class Bound extends TBound {
abstract string toString();
/** Gets an expression that equals this bound plus `delta`. */
abstract Instruction getInstruction(int delta);
/** Gets an expression that equals this bound. */
Instruction getInstruction() { result = getInstruction(0) }
abstract Location getLocation();
}
/**
* The bound that corresponds to the integer 0. This is used to represent all
* integer bounds as bounds are always accompanied by an added integer delta.
*/
class ZeroBound extends Bound, TBoundZero {
override string toString() { result = "0" }
override Instruction getInstruction(int delta) {
result.(ConstantValueInstruction).getValue().toInt() = delta
}
override Location getLocation() { result instanceof UnknownDefaultLocation }
}
/**
* A bound corresponding to the value of an `Instruction`.
*/
class ValueNumberBound extends Bound, TBoundValueNumber {
ValueNumber vn;
ValueNumberBound() { this = TBoundValueNumber(vn) }
/** Gets an `Instruction` that equals this bound. */
override Instruction getInstruction(int delta) {
this = TBoundValueNumber(valueNumber(result)) and delta = 0
}
override string toString() { result = "ValueNumberBound" }
override Location getLocation() { result = vn.getLocation() }
/** Gets the value number that equals this bound. */
ValueNumber getValueNumber() { result = vn }
}

View File

@@ -2,7 +2,7 @@
* Simple constant analysis using the Semantic interface.
*/
private import experimental.semmle.code.cpp.semantic.Semantic
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import ConstantAnalysisSpecific as Specific
/** An expression that always has the same integer value. */

View File

@@ -2,7 +2,7 @@
* C++-specific implementation of constant analysis.
*/
private import experimental.semmle.code.cpp.semantic.Semantic
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
/**
* Gets the constant integer value of the specified expression, if any.

View File

@@ -11,7 +11,7 @@
*/
private import ModulusAnalysisSpecific::Private
private import experimental.semmle.code.cpp.semantic.Semantic
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import ConstantAnalysis
private import RangeUtils
private import RangeAnalysisStage

View File

@@ -2,7 +2,7 @@
* C++-specific implementation of modulus analysis.
*/
module Private {
private import experimental.semmle.code.cpp.semantic.Semantic
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
predicate ignoreExprModulus(SemExpr e) { none() }
}

View File

@@ -0,0 +1,3 @@
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
private import RangeAnalysisImpl as Impl
import Impl::Public

View File

@@ -1,10 +1,10 @@
private import RangeAnalysisStage
private import RangeAnalysisSpecific
private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
private import RangeUtils
private import experimental.semmle.code.cpp.semantic.SemanticBound as SemanticBound
private import experimental.semmle.code.cpp.semantic.SemanticLocation
private import experimental.semmle.code.cpp.semantic.SemanticSSA
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound as SemanticBound
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticSSA
module ConstantBounds implements BoundSig<FloatDelta> {
class SemBound instanceof SemanticBound::SemBound {

View File

@@ -2,9 +2,9 @@
* C++-specific implementation of range analysis.
*/
private import experimental.semmle.code.cpp.semantic.Semantic
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import RangeAnalysisStage
private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
module CppLangImpl implements LangSig<FloatDelta> {
/**

View File

@@ -2,10 +2,10 @@
* C++-specific implementation of range analysis.
*/
private import experimental.semmle.code.cpp.semantic.Semantic
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import RangeAnalysisStage
private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
private import experimental.semmle.code.cpp.semantic.analysis.IntDelta
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.IntDelta
private import RangeAnalysisImpl
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils

View File

@@ -65,32 +65,29 @@
private import RangeUtils as Utils
private import SignAnalysisCommon
private import experimental.semmle.code.cpp.semantic.analysis.ModulusAnalysis
import experimental.semmle.code.cpp.semantic.SemanticExpr
import experimental.semmle.code.cpp.semantic.SemanticSSA
import experimental.semmle.code.cpp.semantic.SemanticGuard
import experimental.semmle.code.cpp.semantic.SemanticCFG
import experimental.semmle.code.cpp.semantic.SemanticType
import experimental.semmle.code.cpp.semantic.SemanticOpcode
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.ModulusAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticSSA
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticType
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticOpcode
private import ConstantAnalysis
private import Sign
import experimental.semmle.code.cpp.semantic.SemanticLocation
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
/**
* Holds if `typ` is a small integral type with the given lower and upper bounds.
*/
private predicate typeBound(SemIntegerType typ, int lowerbound, int upperbound) {
private predicate typeBound(SemIntegerType typ, float lowerbound, float upperbound) {
exists(int bitSize | bitSize = typ.getByteSize() * 8 |
bitSize < 32 and
(
if typ.isSigned()
then (
upperbound = 1.bitShiftLeft(bitSize - 1) - 1 and
lowerbound = -upperbound - 1
) else (
lowerbound = 0 and
upperbound = 1.bitShiftLeft(bitSize) - 1
)
if typ.isSigned()
then (
upperbound = 2.pow(bitSize - 1) - 1 and
lowerbound = -upperbound - 1
) else (
lowerbound = 0 and
upperbound = 2.pow(bitSize) - 1
)
)
}
@@ -295,10 +292,10 @@ module RangeStage<
}
/** Gets the lower bound of the resulting type. */
int getLowerBound() { typeBound(getTrackedType(this), result, _) }
float getLowerBound() { typeBound(getTrackedType(this), result, _) }
/** Gets the upper bound of the resulting type. */
int getUpperBound() { typeBound(getTrackedType(this), _, result) }
float getUpperBound() { typeBound(getTrackedType(this), _, result) }
}
private module SignAnalysisInstantiated = SignAnalysis<D, UtilParam>; // TODO: will this cause reevaluation if it's instantiated with the same DeltaSig and UtilParam multiple times?

View File

@@ -2,7 +2,7 @@
* Provides utility predicates for range analysis.
*/
private import experimental.semmle.code.cpp.semantic.Semantic
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import RangeAnalysisSpecific
private import RangeAnalysisStage as Range
private import ConstantAnalysis

View File

@@ -1,4 +1,4 @@
private import experimental.semmle.code.cpp.semantic.Semantic
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
newtype TSign =
TNeg() or

View File

@@ -8,7 +8,7 @@
private import RangeAnalysisStage
private import SignAnalysisSpecific as Specific
private import experimental.semmle.code.cpp.semantic.Semantic
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
private import ConstantAnalysis
private import RangeUtils
private import Sign

View File

@@ -2,7 +2,7 @@
* Provides C++-specific definitions for use in sign analysis.
*/
private import experimental.semmle.code.cpp.semantic.Semantic
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
/**
* Workaround to allow certain expressions to have a negative sign, even if the type of the

View File

@@ -1820,24 +1820,26 @@ new_array_allocated_type(
/**
* The field being initialized by an initializer expression within an aggregate
* initializer for a class/struct/union.
* initializer for a class/struct/union. Position is used to sort repeated initializers.
*/
#keyset[aggregate, field]
#keyset[aggregate, position]
aggregate_field_init(
int aggregate: @aggregateliteral ref,
int initializer: @expr ref,
int field: @membervariable ref
int field: @membervariable ref,
int position: int ref
);
/**
* The index of the element being initialized by an initializer expression
* within an aggregate initializer for an array.
* within an aggregate initializer for an array. Position is used to sort repeated initializers.
*/
#keyset[aggregate, element_index]
#keyset[aggregate, position]
aggregate_array_init(
int aggregate: @aggregateliteral ref,
int initializer: @expr ref,
int element_index: int ref
int element_index: int ref,
int position: int ref
);
@ctorinit = @ctordirectinit

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
class AggregateLiteral extends @aggregateliteral {
string toString() { none() }
}
class Expr extends @expr {
string toString() { none() }
}
from AggregateLiteral al, Expr init, int index, int position
where exprparents(init, position, al) and aggregate_array_init(al, init, index)
select al, init, index, position

View File

@@ -0,0 +1,15 @@
class AggregateLiteral extends @aggregateliteral {
string toString() { none() }
}
class Expr extends @expr {
string toString() { none() }
}
class Field extends @membervariable {
string toString() { none() }
}
from AggregateLiteral al, Expr init, Field field, int position
where exprparents(init, position, al) and aggregate_field_init(al, init, field)
select al, init, field, position

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
description: Support repeated initializers, which are allowed in C with designated initializers.
compatibility: full
aggregate_field_init.rel: run aggregate_field_init.qlo
aggregate_array_init.rel: run aggregate_array_init.qlo

View File

@@ -48,11 +48,11 @@ predicate case1(FunctionCall fc, Expr sizeArg, VariableAccess destArg) {
* Holds if `fc` is a call to `strncat` with size argument `sizeArg` and destination
* argument `destArg`, and `sizeArg` computes the value `sizeof (dest) - strlen (dest)`.
*/
predicate case2(FunctionCall fc, Expr sizeArg, VariableAccess destArg) {
interestingCallWithArgs(fc, sizeArg, destArg) and
predicate case2(FunctionCall fc, Expr sizeArg, Expr destArg) {
interestingCallWithArgs(fc, pragma[only_bind_into](sizeArg), pragma[only_bind_into](destArg)) and
exists(SubExpr sub, int n |
// The destination buffer is an array of size n
destArg.getUnspecifiedType().(ArrayType).getSize() = n and
pragma[only_bind_out](destArg.getUnspecifiedType().(ArrayType).getSize()) = n and
// The size argument is equivalent to a subtraction
globalValueNumber(sizeArg).getAnExpr() = sub and
// ... where the left side of the subtraction is the constant n

View File

@@ -11,9 +11,9 @@
import cpp
import experimental.semmle.code.cpp.dataflow.ProductFlow
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
import experimental.semmle.code.cpp.rangeanalysis.Bound
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.Bound
import semmle.code.cpp.ir.IR
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.models.interfaces.Allocation

View File

@@ -17,9 +17,8 @@ import experimental.semmle.code.cpp.dataflow.ProductFlow
import semmle.code.cpp.ir.IR
import semmle.code.cpp.models.interfaces.Allocation
import semmle.code.cpp.models.interfaces.ArrayFunction
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
import experimental.semmle.code.cpp.semantic.SemanticBound
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import DataFlow::PathGraph
pragma[nomagic]

View File

@@ -10,9 +10,8 @@
* experimental
*/
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
import experimental.semmle.code.cpp.semantic.SemanticBound
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.DataFlow
import PointerArithmeticToDerefFlow::PathGraph

View File

@@ -17,9 +17,8 @@
import cpp
import experimental.semmle.code.cpp.dataflow.ProductFlow
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
import experimental.semmle.code.cpp.semantic.SemanticBound
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR
pragma[nomagic]

View File

@@ -1,11 +1,11 @@
import cpp
import experimental.semmle.code.cpp.semantic.analysis.ModulusAnalysis
import experimental.semmle.code.cpp.semantic.Semantic
import experimental.semmle.code.cpp.semantic.analysis.RangeUtils
import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisSpecific
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisImpl
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.ModulusAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisImpl
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR as IR
import TestUtilities.InlineExpectationsTest

View File

@@ -1,5 +1,5 @@
import cpp
import experimental.semmle.code.cpp.semantic.analysis.SimpleRangeAnalysis
import semmle.code.cpp.rangeanalysis.new.SimpleRangeAnalysis
import TestUtilities.InlineExpectationsTest
class RangeAnalysisTest extends InlineExpectationsTest {

View File

@@ -1,7 +1,7 @@
import cpp
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
import experimental.semmle.code.cpp.semantic.Semantic
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR as IR
import TestUtilities.InlineExpectationsTest

View File

@@ -411,7 +411,7 @@ int test_mult03(int a, int b) {
if (-17 <= a && a <= 11 && -13 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=-17
range(b); // $ range=<=23 range=>=-13
int r = a*b; //3 $ overflow=+- -391 .. 25
int r = a*b; // $ overflow=+- -391 .. 25
range(r);
total += r; // $ overflow=+-
range(total);
@@ -566,11 +566,11 @@ unsigned int test_ternary01(unsigned int x) {
y1 = x < 100 ?
(range(x), x) : // $ range=<=99
(range(x), 10); // $ range=>=100
range(y1);
range(y1); // $ range=<=99
y2 = x >= 100 ?
(range(x), 10) : // $ range=>=100
(range(x), x); // $ range=<=99
range(y2);
range(y2); // $ range=<=99
y3 = 0;
y4 = 0;
y5 = 0;
@@ -580,14 +580,14 @@ unsigned int test_ternary01(unsigned int x) {
if (x < 300) {
range(x); // $ range=<=299
y3 = x ?:
(range(x), 5); // y3 < 300
range(y3);
(range(x), 5);
range(y3); // $ range=<=299
y4 = x ?:
(range(x), 500); // y4 <= 500
range(y4);
(range(x), 500);
range(y4); // $ range=<=500
y5 = (x+1) ?:
(range(x), 500); // $ overflow=- range===-1
range(y5); // y5 <= 300
range(y5); // $ range=<=500
y6 = ((unsigned char)(x+1)) ?:
(range(x), 5); // $ range=<=299
range(y6); // y6 < 256
@@ -608,11 +608,11 @@ unsigned int test_ternary02(unsigned int x) {
y1 = x > 100 ?
(range(x), x) : // $ range=>=101
(range(x), 110); // $ range=<=100
range(y1); // y1 > 100
range(y1); // $ range=>=101
y2 = x <= 100 ?
(range(x), 110) : // $ range=<=100
(range(x), x); // $ range=>=101
range(y2); // y2 > 100
range(y2); // $ range=>=101
y3 = 1000;
y4 = 1000;
y5 = 1000;
@@ -620,15 +620,15 @@ unsigned int test_ternary02(unsigned int x) {
range(x); // $ range=>=300
y3 = (x-300) ?:
(range(x), 5); // $ range===300
range(y3); // y3 >= 0
range(y3); // $ range=>=0
y4 = (x-200) ?:
(range(x), 5); // $ range=<=200 range=>=300
range(y4); // y4 >= 100
range(y4); // $ SPURIOUS: range=>=5 MISSING: range=>=100
y5 = ((unsigned char)(x-200)) ?:
(range(x), 5); // $ range=>=300
range(y5); // y6 >= 0
}
range(y1 + y2 + y3 + y4 + y5); // $ overflow=+ MISSING: range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
range(y1 + y2 + y3 + y4 + y5); // $ overflow=+ MISSING: range=">=call to range+207" range=">=... = ...:... ? ... : ...+0" range=">=call to range+0"
return y1 + y2 + y3 + y4 + y5; // $ overflow=+
}
@@ -640,15 +640,15 @@ unsigned int test_comma01(unsigned int x) {
unsigned int y1;
unsigned int y2;
y1 = (++y, y);
range(y1); // $ range="==... ? ... : ...+1"
range(y1); // $ range=<=101 range="==... ? ... : ...+1"
y2 = (y++,
range(y), // $ range="==++ ...:... = ...+1" range="==... ? ... : ...+2"
range(y), // $ range=<=102 range="==++ ...:... = ...+1" range="==... ? ... : ...+2"
y += 3,
range(y), // $ range="==++ ...:... = ...+4" range="==... +++3" range="==... ? ... : ...+5"
range(y), // $ range=<=105 range="==++ ...:... = ...+4" range="==... +++3" range="==... ? ... : ...+5"
y);
range(y2); // $ range="==++ ...:... = ...+4" range="==... +++3" range="==... ? ... : ...+5"
range(y1 + y2); // $ overflow=+ MISSING: range=">=++ ...:... = ...+5" range=">=... +++4" range=">=... += ...:... = ...+1" range=">=... ? ... : ...+6"
return y1 + y2; // $ overflow=+
range(y2); // $ range=<=105 range="==++ ...:... = ...+4" range="==... +++3" range="==... ? ... : ...+5"
range(y1 + y2); // $ range=<=206 range="<=... ? ... : ...+106" MISSING: range=">=++ ...:... = ...+5" range=">=... +++4" range=">=... += ...:... = ...+1" range=">=... ? ... : ...+6"
return y1 + y2;
}
void test17() {
@@ -683,27 +683,27 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
range(a); // $ range=<=11 range=>=3
range(b); // $ range=<=23 range=>=5
int r = a*b; // 15 .. 253
range(r);
range(r); // $ range=>=15 range=<=253
total += r;
range(total); // $ MISSING: range=>=1
range(total); // $ range=>=15 range=<=253
}
if (3 <= a && a <= 11 && 0 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=3
range(b); // $ range=<=23 range=>=0
int r = a*b; // 0 .. 253
range(r);
total += r; // $ overflow=+
range(total); // $ MISSING: range=">=(unsigned int)...+0" range=>=0
range(r);// $ range=>=0 range=<=253
total += r;
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range=<=506 range="<=(unsigned int)...+253"
}
if (3 <= a && a <= 11 && 13 <= b && b <= 23) {
range(a); // $ range=<=11 range=>=3
range(b); // $ range=<=23 range=>=13
int r = a*b; // 39 .. 253
range(r);
total += r; // $ overflow=+
range(total); // $ MISSING: range=">=(unsigned int)...+1" range=>=1
range(r); // $ range=>=39 range=<=253
total += r;
range(total); // $ range=>=39 range=<=759 range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+39"
}
range(total); // $ MISSING: range=">=(unsigned int)...+0" range=>=0
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
return total;
}
@@ -713,25 +713,25 @@ int test_unsigned_mult02(unsigned b) {
if (5 <= b && b <= 23) {
range(b); // $ range=<=23 range=>=5
int r = 11*b; // 55 .. 253
range(r);
range(r); // $ range=>=55 range=<=253
total += r;
range(total); // $ MISSING: range=>=1
range(total); // $ range=>=55 range=<=253
}
if (0 <= b && b <= 23) {
range(b); // $ range=<=23 range=>=0
int r = 11*b; // 0 .. 253
range(r);
total += r; // $ overflow=+
range(total); // $ MISSING: range=">=(unsigned int)...+0" range=>=0
range(r); // $ range=>=0 range=<=253
total += r;
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range="<=(unsigned int)...+253" range=<=506
}
if (13 <= b && b <= 23) {
range(b); // $ range=<=23 range=>=13
int r = 11*b; // 143 .. 253
range(r);
total += r; // $ overflow=+
range(total); // $ MISSING: range=">=(unsigned int)...+1" range=>=1
range(r); // $ range=>=143 range=<=253
total += r;
range(total); // $ range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+143" range=>=143 range=<=759
}
range(total); // $ MISSING: range=">=(unsigned int)...+0" range=>=0
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
return total;
}
@@ -888,7 +888,7 @@ void notequal_variations(short n, float f) {
}
if (n >= 5) {
if (2 * n - 10 == 0) { // $ overflow=+ Same as `n == 10/2` (modulo overflow)
if (2 * n - 10 == 0) { // $ overflow=+
range(n); // $ range=>=5 MISSING: range===5
return;
}

View File

@@ -1,10 +1,10 @@
import cpp
import experimental.semmle.code.cpp.semantic.analysis.SignAnalysisCommon
import experimental.semmle.code.cpp.semantic.Semantic
import experimental.semmle.code.cpp.semantic.analysis.RangeUtils
import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisSpecific
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.SignAnalysisCommon
import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeUtils
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysisSpecific
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
import semmle.code.cpp.ir.IR as IR
import TestUtilities.InlineExpectationsTest