mirror of
https://github.com/github/codeql.git
synced 2025-12-23 20:26:32 +01:00
Merge branch 'main' into rdmarsh2/range-analysis-overflow
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import experimental.semmle.code.cpp.semantic.SemanticBound
|
||||
private import RangeAnalysisImpl as Impl
|
||||
import Impl::Public
|
||||
@@ -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, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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. */
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticBound
|
||||
private import RangeAnalysisImpl as Impl
|
||||
import Impl::Public
|
||||
@@ -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 {
|
||||
@@ -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> {
|
||||
/**
|
||||
@@ -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
|
||||
|
||||
@@ -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?
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user