mirror of
https://github.com/github/codeql.git
synced 2025-12-23 12:16:33 +01:00
135 lines
3.7 KiB
Plaintext
135 lines
3.7 KiB
Plaintext
import cpp
|
|
private import semmle.code.cpp.ir.IR
|
|
// TODO: move this dependency
|
|
import semmle.code.cpp.ir.internal.IntegerConstant
|
|
|
|
// TODO: move this out of test code
|
|
language[monotonicAggregates]
|
|
IntValue getConstantValue(Instruction instr) {
|
|
result = instr.(IntegerConstantInstruction).getValue().toInt()
|
|
or
|
|
exists(BinaryInstruction binInstr, IntValue left, IntValue right |
|
|
binInstr = instr and
|
|
left = getConstantValue(binInstr.getLeft()) and
|
|
right = getConstantValue(binInstr.getRight()) and
|
|
(
|
|
binInstr instanceof AddInstruction and result = add(left, right)
|
|
or
|
|
binInstr instanceof SubInstruction and result = sub(left, right)
|
|
or
|
|
binInstr instanceof MulInstruction and result = mul(left, right)
|
|
or
|
|
binInstr instanceof DivInstruction and result = div(left, right)
|
|
)
|
|
)
|
|
or
|
|
result = getConstantValue(instr.(CopyInstruction).getSourceValue())
|
|
or
|
|
exists(PhiInstruction phi |
|
|
phi = instr and
|
|
result =
|
|
max(PhiInputOperand operand |
|
|
operand = phi.getAnOperand()
|
|
|
|
|
getConstantValue(operand.getDef())
|
|
) and
|
|
result =
|
|
min(PhiInputOperand operand |
|
|
operand = phi.getAnOperand()
|
|
|
|
|
getConstantValue(operand.getDef())
|
|
)
|
|
)
|
|
}
|
|
|
|
predicate valueFlowStep(Instruction i, Operand op, int delta) {
|
|
i.(CopyInstruction).getSourceValueOperand() = op and delta = 0
|
|
or
|
|
exists(Operand x |
|
|
i.(AddInstruction).getAnOperand() = op and
|
|
i.(AddInstruction).getAnOperand() = x and
|
|
op != x
|
|
|
|
|
delta = getValue(getConstantValue(x.getDef()))
|
|
)
|
|
or
|
|
exists(Operand x |
|
|
i.(SubInstruction).getLeftOperand() = op and
|
|
i.(SubInstruction).getRightOperand() = x
|
|
|
|
|
delta = -getValue(getConstantValue(x.getDef()))
|
|
)
|
|
or
|
|
exists(Operand x |
|
|
i.(PointerAddInstruction).getAnOperand() = op and
|
|
i.(PointerAddInstruction).getAnOperand() = x and
|
|
op != x
|
|
|
|
|
delta = i.(PointerAddInstruction).getElementSize() * getValue(getConstantValue(x.getDef()))
|
|
)
|
|
or
|
|
exists(Operand x |
|
|
i.(PointerSubInstruction).getLeftOperand() = op and
|
|
i.(PointerSubInstruction).getRightOperand() = x
|
|
|
|
|
delta = i.(PointerSubInstruction).getElementSize() * -getValue(getConstantValue(x.getDef()))
|
|
)
|
|
}
|
|
|
|
predicate backEdge(PhiInstruction phi, PhiInputOperand op) {
|
|
phi.getAnOperand() = op and
|
|
phi.getBlock() = op.getPredecessorBlock().getBackEdgeSuccessor(_)
|
|
}
|
|
|
|
/**
|
|
* Holds if a cast from `fromtyp` to `totyp` can be ignored for the purpose of
|
|
* range analysis.
|
|
*/
|
|
pragma[inline]
|
|
private predicate safeCast(IRIntegerType fromtyp, IRIntegerType totyp) {
|
|
fromtyp.getByteSize() < totyp.getByteSize() and
|
|
(
|
|
fromtyp.isUnsigned()
|
|
or
|
|
totyp.isSigned()
|
|
)
|
|
or
|
|
fromtyp.getByteSize() <= totyp.getByteSize() and
|
|
(
|
|
fromtyp.isSigned() and
|
|
totyp.isSigned()
|
|
or
|
|
fromtyp.isUnsigned() and
|
|
totyp.isUnsigned()
|
|
)
|
|
}
|
|
|
|
/**
|
|
* A `ConvertInstruction` which casts from one pointer type to another.
|
|
*/
|
|
class PtrToPtrCastInstruction extends ConvertInstruction {
|
|
PtrToPtrCastInstruction() {
|
|
getResultIRType() instanceof IRAddressType and
|
|
getUnary().getResultIRType() instanceof IRAddressType
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A `ConvertInstruction` which casts from one integer type to another in a way
|
|
* that cannot overflow or underflow.
|
|
*/
|
|
class SafeIntCastInstruction extends ConvertInstruction {
|
|
SafeIntCastInstruction() { safeCast(getUnary().getResultIRType(), getResultIRType()) }
|
|
}
|
|
|
|
/**
|
|
* A `ConvertInstruction` which does not invalidate bounds determined by
|
|
* range analysis.
|
|
*/
|
|
class SafeCastInstruction extends ConvertInstruction {
|
|
SafeCastInstruction() {
|
|
this instanceof PtrToPtrCastInstruction or
|
|
this instanceof SafeIntCastInstruction
|
|
}
|
|
}
|