mirror of
https://github.com/github/codeql.git
synced 2026-05-02 20:25:13 +02:00
Merge branch 'master' into master
This commit is contained in:
@@ -29,7 +29,7 @@ from BufferAccess ba, string bufferDesc, int accessSize, int accessType,
|
||||
where accessSize = ba.getSize()
|
||||
and bufferSize = getBufferSize(ba.getBuffer(bufferDesc, accessType),
|
||||
bufferAlloc)
|
||||
and accessSize > bufferSize
|
||||
and (accessSize > bufferSize or (accessSize <= 0 and accessType = 3))
|
||||
and if accessType = 1 then (
|
||||
message = "This '" + ba.getName() + "' operation accesses "
|
||||
+ plural(accessSize, " byte", " bytes")
|
||||
@@ -41,8 +41,13 @@ where accessSize = ba.getSize()
|
||||
+ " but the $@ is only "
|
||||
+ plural(bufferSize, " byte", " bytes") + "."
|
||||
) else (
|
||||
message = "This array indexing operation accesses byte offset "
|
||||
+ (accessSize - 1) + " but the $@ is only "
|
||||
+ plural(bufferSize, " byte", " bytes") + "."
|
||||
if accessSize > 0 then (
|
||||
message = "This array indexing operation accesses byte offset "
|
||||
+ (accessSize - 1) + " but the $@ is only "
|
||||
+ plural(bufferSize, " byte", " bytes") + "."
|
||||
) else (
|
||||
message = "This array indexing operation accesses a negative index "
|
||||
+ ((accessSize/ba.getActualType().getSize()) - 1) + " on the $@."
|
||||
)
|
||||
)
|
||||
select ba, message, bufferAlloc, bufferDesc
|
||||
|
||||
@@ -14,6 +14,7 @@ import semmle.code.cpp.dataflow.DataFlow2
|
||||
import semmle.code.cpp.dataflow.DataFlow3
|
||||
import semmle.code.cpp.dataflow.DataFlow4
|
||||
import semmle.code.cpp.dataflow.TaintTracking
|
||||
import semmle.code.cpp.valuenumbering.HashCons
|
||||
|
||||
from File f, string tag
|
||||
where none()
|
||||
|
||||
1
cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll
Normal file
1
cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll
Normal file
@@ -0,0 +1 @@
|
||||
import implementation.aliased_ssa.PrintIR
|
||||
1
cpp/ql/src/semmle/code/cpp/ir/ValueNumbering.qll
Normal file
1
cpp/ql/src/semmle/code/cpp/ir/ValueNumbering.qll
Normal file
@@ -0,0 +1 @@
|
||||
import implementation.aliased_ssa.gvn.ValueNumbering
|
||||
@@ -5,3 +5,30 @@ import IRVariable
|
||||
import OperandTag
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
|
||||
private newtype TIRPropertyProvider = MkIRPropertyProvider()
|
||||
|
||||
/**
|
||||
* Class that provides additional properties to be dumped for IR instructions and blocks when using
|
||||
* the PrintIR module. Libraries that compute additional facts about IR elements can extend the
|
||||
* single instance of this class to specify the additional properties computed by the library.
|
||||
*/
|
||||
class IRPropertyProvider extends TIRPropertyProvider {
|
||||
string toString() {
|
||||
result = "IRPropertyProvider"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified instruction.
|
||||
*/
|
||||
string getInstructionProperty(Instruction instruction, string key) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified block.
|
||||
*/
|
||||
string getBlockProperty(IRBlock block, string key) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,14 @@ module InstructionSanity {
|
||||
operand = op.getOperand(tag) and
|
||||
operand.getFunctionIR() != op.getFunctionIR()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,6 +309,13 @@ class Instruction extends Construction::TInstruction {
|
||||
result = ast.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Expr` whose results is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getResultExpression() {
|
||||
result = Construction::getInstructionResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
* instruction does not produce a result, its result type will be `VoidType`.
|
||||
@@ -554,6 +569,15 @@ class InitializeParameterInstruction extends VariableInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes the `this` pointer parameter of the enclosing function.
|
||||
*/
|
||||
class InitializeThisInstruction extends Instruction {
|
||||
InitializeThisInstruction() {
|
||||
opcode instanceof Opcode::InitializeThis
|
||||
}
|
||||
}
|
||||
|
||||
class FieldAddressInstruction extends FieldInstruction {
|
||||
FieldAddressInstruction() {
|
||||
opcode instanceof Opcode::FieldAddress
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
private import IR
|
||||
import cpp
|
||||
|
||||
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getInstructionProperty(instr, key)
|
||||
)
|
||||
}
|
||||
|
||||
private string getAdditionalBlockProperty(IRBlock block, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getBlockProperty(block, key)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableFunctionIR(FunctionIR funcIR) or
|
||||
TPrintableIRBlock(IRBlock block) or
|
||||
@@ -135,6 +147,11 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||
result.getFunctionIR() = block.getFunctionIR()
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = PrintableIRNode.super.getProperty(key) or
|
||||
result = getAdditionalBlockProperty(block, key)
|
||||
}
|
||||
|
||||
final IRBlock getBlock() {
|
||||
result = block
|
||||
}
|
||||
@@ -185,6 +202,11 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||
final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = PrintableIRNode.super.getProperty(key) or
|
||||
result = getAdditionalInstructionProperty(instr, key)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
private import internal.ValueNumberingInternal
|
||||
import cpp
|
||||
private import IR
|
||||
|
||||
/**
|
||||
* Provides additional information about value numbering in IR dumps.
|
||||
*/
|
||||
class ValueNumberPropertyProvider extends IRPropertyProvider {
|
||||
override string getInstructionProperty(Instruction instr, string key) {
|
||||
exists(ValueNumber vn |
|
||||
vn = valueNumber(instr) and
|
||||
key = "valnum" and
|
||||
if strictcount(vn.getAnInstruction()) > 1 then
|
||||
result = vn.toString()
|
||||
else
|
||||
result = "unique"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(FunctionIR funcIR, IRVariable var) {
|
||||
variableAddressValueNumber(_, funcIR, var)
|
||||
} or
|
||||
TInitializeParameterValueNumber(FunctionIR funcIR, IRVariable var) {
|
||||
initializeParameterValueNumber(_, funcIR, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(FunctionIR funcIR) {
|
||||
initializeThisValueNumber(_, funcIR)
|
||||
} or
|
||||
TConstantValueNumber(FunctionIR funcIR, Type type, string value) {
|
||||
constantValueNumber(_, funcIR, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(FunctionIR funcIR, Field field, ValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, funcIR, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand) {
|
||||
binaryValueNumber(_, funcIR, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(FunctionIR funcIR, Opcode opcode, Type type, int elementSize,
|
||||
ValueNumber leftOperand, ValueNumber rightOperand) {
|
||||
pointerArithmeticValueNumber(_, funcIR, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber operand) {
|
||||
unaryValueNumber(_, funcIR, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(FunctionIR funcIR, Opcode opcode, Class baseClass,
|
||||
Class derivedClass, ValueNumber operand) {
|
||||
inheritanceConversionValueNumber(_, funcIR, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
TUniqueValueNumber(FunctionIR funcIR, Instruction instr) {
|
||||
uniqueValueNumber(instr, funcIR)
|
||||
}
|
||||
|
||||
/**
|
||||
* The value number assigned to a particular set of instructions that produce equivalent results.
|
||||
*/
|
||||
class ValueNumber extends TValueNumber {
|
||||
final string toString() {
|
||||
result = getExampleInstruction().getResultId()
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
result = getExampleInstruction().getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instructions that have been assigned this value number. This will always produce at
|
||||
* least one result.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
this = valueNumber(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one of the instructions that was assigned this value number. The chosen instuction is
|
||||
* deterministic but arbitrary. Intended for use only in debugging.
|
||||
*/
|
||||
final Instruction getExampleInstruction() {
|
||||
result = min(Instruction instr |
|
||||
instr = getAnInstruction() |
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||
* operand.
|
||||
* For example:
|
||||
* ```
|
||||
* Point p = { 1, 2 };
|
||||
* Point q = p;
|
||||
* int a = p.x;
|
||||
* ```
|
||||
* The use of `p` on line 2 is linked to the definition of `p` on line 1, and is congruent to that
|
||||
* definition because it accesses the exact same memory.
|
||||
* The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not
|
||||
* congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`.
|
||||
*
|
||||
* This concept should probably be exposed in the public IR API.
|
||||
*/
|
||||
private class CongruentCopyInstruction extends CopyInstruction {
|
||||
CongruentCopyInstruction() {
|
||||
exists(Instruction def |
|
||||
def = this.getSourceValue() and
|
||||
(
|
||||
def.getResultMemoryAccess() instanceof IndirectMemoryAccess or
|
||||
not def.hasMemoryResult()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this library knows how to assign a value number to the specified instruction, other than
|
||||
* a `unique` value number that is never shared by multiple instructions.
|
||||
*/
|
||||
private predicate numberableInstruction(Instruction instr) {
|
||||
instr instanceof VariableAddressInstruction or
|
||||
instr instanceof InitializeParameterInstruction or
|
||||
instr instanceof InitializeThisInstruction or
|
||||
instr instanceof ConstantInstruction or
|
||||
instr instanceof FieldAddressInstruction or
|
||||
instr instanceof BinaryInstruction or
|
||||
instr instanceof UnaryInstruction or
|
||||
instr instanceof PointerArithmeticInstruction or
|
||||
instr instanceof CongruentCopyInstruction
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(VariableAddressInstruction instr, FunctionIR funcIR,
|
||||
IRVariable var) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(InitializeParameterInstruction instr,
|
||||
FunctionIR funcIR, IRVariable var) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, FunctionIR funcIR) {
|
||||
instr.getFunctionIR() = funcIR
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(ConstantInstruction instr, FunctionIR funcIR, Type type,
|
||||
string value) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getResultType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(FieldAddressInstruction instr, FunctionIR funcIR,
|
||||
Field field, ValueNumber objectAddress) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getField() = field and
|
||||
valueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(BinaryInstruction instr, FunctionIR funcIR, Opcode opcode,
|
||||
Type type, ValueNumber leftOperand, ValueNumber rightOperand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
(not instr instanceof PointerArithmeticInstruction) and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
valueNumber(instr.getLeftOperand()) = leftOperand and
|
||||
valueNumber(instr.getRightOperand()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(PointerArithmeticInstruction instr,
|
||||
FunctionIR funcIR, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
valueNumber(instr.getLeftOperand()) = leftOperand and
|
||||
valueNumber(instr.getRightOperand()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(UnaryInstruction instr, FunctionIR funcIR, Opcode opcode,
|
||||
Type type, ValueNumber operand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
(not instr instanceof InheritanceConversionInstruction) and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
valueNumber(instr.getOperand()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(InheritanceConversionInstruction instr,
|
||||
FunctionIR funcIR, Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getBaseClass() = baseClass and
|
||||
instr.getDerivedClass() = derivedClass and
|
||||
valueNumber(instr.getOperand()) = operand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr, FunctionIR funcIR) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
(not instr.getResultType() instanceof VoidType) and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any. Returns at most one result.
|
||||
*/
|
||||
ValueNumber valueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr) or
|
||||
exists(FunctionIR funcIR |
|
||||
uniqueValueNumber(instr, funcIR) and
|
||||
result = TUniqueValueNumber(funcIR, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
|
||||
* value number.
|
||||
*/
|
||||
private ValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = instr.getFunctionIR() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, funcIR, var) and
|
||||
result = TVariableAddressValueNumber(funcIR, var)
|
||||
) or
|
||||
exists(IRVariable var |
|
||||
initializeParameterValueNumber(instr, funcIR, var) and
|
||||
result = TInitializeParameterValueNumber(funcIR, var)
|
||||
) or
|
||||
(
|
||||
initializeThisValueNumber(instr, funcIR) and
|
||||
result = TInitializeThisValueNumber(funcIR)
|
||||
) or
|
||||
exists(Type type, string value |
|
||||
constantValueNumber(instr, funcIR, type, value) and
|
||||
result = TConstantValueNumber(funcIR, type, value)
|
||||
) or
|
||||
exists(Field field, ValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, funcIR, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(funcIR, field, objectAddress)
|
||||
) or
|
||||
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
binaryValueNumber(instr, funcIR, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(funcIR, opcode, type, leftOperand, rightOperand)
|
||||
) or
|
||||
exists(Opcode opcode, Type type, ValueNumber operand |
|
||||
unaryValueNumber(instr, funcIR, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(funcIR, opcode, type, operand)
|
||||
) or
|
||||
exists(Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand |
|
||||
inheritanceConversionValueNumber(instr, funcIR, opcode, baseClass, derivedClass,
|
||||
operand) and
|
||||
result = TInheritanceConversionValueNumber(funcIR, opcode, baseClass, derivedClass, operand)
|
||||
) or
|
||||
exists(Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, funcIR, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(funcIR, opcode, type, elementSize, leftOperand,
|
||||
rightOperand)
|
||||
) or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as IR
|
||||
@@ -30,7 +30,9 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
cached newtype TInstructionTag =
|
||||
WrappedInstructionTag(OldIR::Instruction oldInstruction) or
|
||||
WrappedInstructionTag(OldIR::Instruction oldInstruction) {
|
||||
not oldInstruction instanceof OldIR::PhiInstruction
|
||||
} or
|
||||
PhiTag(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
hasPhiNode(vvar, block)
|
||||
}
|
||||
@@ -195,6 +197,10 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Expr getInstructionResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getResultExpression()
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
|
||||
}
|
||||
|
||||
@@ -5,3 +5,30 @@ import IRVariable
|
||||
import OperandTag
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
|
||||
private newtype TIRPropertyProvider = MkIRPropertyProvider()
|
||||
|
||||
/**
|
||||
* Class that provides additional properties to be dumped for IR instructions and blocks when using
|
||||
* the PrintIR module. Libraries that compute additional facts about IR elements can extend the
|
||||
* single instance of this class to specify the additional properties computed by the library.
|
||||
*/
|
||||
class IRPropertyProvider extends TIRPropertyProvider {
|
||||
string toString() {
|
||||
result = "IRPropertyProvider"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified instruction.
|
||||
*/
|
||||
string getInstructionProperty(Instruction instruction, string key) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified block.
|
||||
*/
|
||||
string getBlockProperty(IRBlock block, string key) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,14 @@ module InstructionSanity {
|
||||
operand = op.getOperand(tag) and
|
||||
operand.getFunctionIR() != op.getFunctionIR()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,6 +309,13 @@ class Instruction extends Construction::TInstruction {
|
||||
result = ast.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Expr` whose results is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getResultExpression() {
|
||||
result = Construction::getInstructionResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
* instruction does not produce a result, its result type will be `VoidType`.
|
||||
@@ -554,6 +569,15 @@ class InitializeParameterInstruction extends VariableInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes the `this` pointer parameter of the enclosing function.
|
||||
*/
|
||||
class InitializeThisInstruction extends Instruction {
|
||||
InitializeThisInstruction() {
|
||||
opcode instanceof Opcode::InitializeThis
|
||||
}
|
||||
}
|
||||
|
||||
class FieldAddressInstruction extends FieldInstruction {
|
||||
FieldAddressInstruction() {
|
||||
opcode instanceof Opcode::FieldAddress
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
private import IR
|
||||
import cpp
|
||||
|
||||
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getInstructionProperty(instr, key)
|
||||
)
|
||||
}
|
||||
|
||||
private string getAdditionalBlockProperty(IRBlock block, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getBlockProperty(block, key)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableFunctionIR(FunctionIR funcIR) or
|
||||
TPrintableIRBlock(IRBlock block) or
|
||||
@@ -135,6 +147,11 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||
result.getFunctionIR() = block.getFunctionIR()
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = PrintableIRNode.super.getProperty(key) or
|
||||
result = getAdditionalBlockProperty(block, key)
|
||||
}
|
||||
|
||||
final IRBlock getBlock() {
|
||||
result = block
|
||||
}
|
||||
@@ -185,6 +202,11 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||
final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = PrintableIRNode.super.getProperty(key) or
|
||||
result = getAdditionalInstructionProperty(instr, key)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
private import internal.ValueNumberingInternal
|
||||
import cpp
|
||||
private import IR
|
||||
|
||||
/**
|
||||
* Provides additional information about value numbering in IR dumps.
|
||||
*/
|
||||
class ValueNumberPropertyProvider extends IRPropertyProvider {
|
||||
override string getInstructionProperty(Instruction instr, string key) {
|
||||
exists(ValueNumber vn |
|
||||
vn = valueNumber(instr) and
|
||||
key = "valnum" and
|
||||
if strictcount(vn.getAnInstruction()) > 1 then
|
||||
result = vn.toString()
|
||||
else
|
||||
result = "unique"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(FunctionIR funcIR, IRVariable var) {
|
||||
variableAddressValueNumber(_, funcIR, var)
|
||||
} or
|
||||
TInitializeParameterValueNumber(FunctionIR funcIR, IRVariable var) {
|
||||
initializeParameterValueNumber(_, funcIR, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(FunctionIR funcIR) {
|
||||
initializeThisValueNumber(_, funcIR)
|
||||
} or
|
||||
TConstantValueNumber(FunctionIR funcIR, Type type, string value) {
|
||||
constantValueNumber(_, funcIR, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(FunctionIR funcIR, Field field, ValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, funcIR, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand) {
|
||||
binaryValueNumber(_, funcIR, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(FunctionIR funcIR, Opcode opcode, Type type, int elementSize,
|
||||
ValueNumber leftOperand, ValueNumber rightOperand) {
|
||||
pointerArithmeticValueNumber(_, funcIR, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber operand) {
|
||||
unaryValueNumber(_, funcIR, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(FunctionIR funcIR, Opcode opcode, Class baseClass,
|
||||
Class derivedClass, ValueNumber operand) {
|
||||
inheritanceConversionValueNumber(_, funcIR, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
TUniqueValueNumber(FunctionIR funcIR, Instruction instr) {
|
||||
uniqueValueNumber(instr, funcIR)
|
||||
}
|
||||
|
||||
/**
|
||||
* The value number assigned to a particular set of instructions that produce equivalent results.
|
||||
*/
|
||||
class ValueNumber extends TValueNumber {
|
||||
final string toString() {
|
||||
result = getExampleInstruction().getResultId()
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
result = getExampleInstruction().getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instructions that have been assigned this value number. This will always produce at
|
||||
* least one result.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
this = valueNumber(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one of the instructions that was assigned this value number. The chosen instuction is
|
||||
* deterministic but arbitrary. Intended for use only in debugging.
|
||||
*/
|
||||
final Instruction getExampleInstruction() {
|
||||
result = min(Instruction instr |
|
||||
instr = getAnInstruction() |
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||
* operand.
|
||||
* For example:
|
||||
* ```
|
||||
* Point p = { 1, 2 };
|
||||
* Point q = p;
|
||||
* int a = p.x;
|
||||
* ```
|
||||
* The use of `p` on line 2 is linked to the definition of `p` on line 1, and is congruent to that
|
||||
* definition because it accesses the exact same memory.
|
||||
* The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not
|
||||
* congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`.
|
||||
*
|
||||
* This concept should probably be exposed in the public IR API.
|
||||
*/
|
||||
private class CongruentCopyInstruction extends CopyInstruction {
|
||||
CongruentCopyInstruction() {
|
||||
exists(Instruction def |
|
||||
def = this.getSourceValue() and
|
||||
(
|
||||
def.getResultMemoryAccess() instanceof IndirectMemoryAccess or
|
||||
not def.hasMemoryResult()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this library knows how to assign a value number to the specified instruction, other than
|
||||
* a `unique` value number that is never shared by multiple instructions.
|
||||
*/
|
||||
private predicate numberableInstruction(Instruction instr) {
|
||||
instr instanceof VariableAddressInstruction or
|
||||
instr instanceof InitializeParameterInstruction or
|
||||
instr instanceof InitializeThisInstruction or
|
||||
instr instanceof ConstantInstruction or
|
||||
instr instanceof FieldAddressInstruction or
|
||||
instr instanceof BinaryInstruction or
|
||||
instr instanceof UnaryInstruction or
|
||||
instr instanceof PointerArithmeticInstruction or
|
||||
instr instanceof CongruentCopyInstruction
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(VariableAddressInstruction instr, FunctionIR funcIR,
|
||||
IRVariable var) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(InitializeParameterInstruction instr,
|
||||
FunctionIR funcIR, IRVariable var) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, FunctionIR funcIR) {
|
||||
instr.getFunctionIR() = funcIR
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(ConstantInstruction instr, FunctionIR funcIR, Type type,
|
||||
string value) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getResultType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(FieldAddressInstruction instr, FunctionIR funcIR,
|
||||
Field field, ValueNumber objectAddress) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getField() = field and
|
||||
valueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(BinaryInstruction instr, FunctionIR funcIR, Opcode opcode,
|
||||
Type type, ValueNumber leftOperand, ValueNumber rightOperand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
(not instr instanceof PointerArithmeticInstruction) and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
valueNumber(instr.getLeftOperand()) = leftOperand and
|
||||
valueNumber(instr.getRightOperand()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(PointerArithmeticInstruction instr,
|
||||
FunctionIR funcIR, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
valueNumber(instr.getLeftOperand()) = leftOperand and
|
||||
valueNumber(instr.getRightOperand()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(UnaryInstruction instr, FunctionIR funcIR, Opcode opcode,
|
||||
Type type, ValueNumber operand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
(not instr instanceof InheritanceConversionInstruction) and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
valueNumber(instr.getOperand()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(InheritanceConversionInstruction instr,
|
||||
FunctionIR funcIR, Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getBaseClass() = baseClass and
|
||||
instr.getDerivedClass() = derivedClass and
|
||||
valueNumber(instr.getOperand()) = operand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr, FunctionIR funcIR) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
(not instr.getResultType() instanceof VoidType) and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any. Returns at most one result.
|
||||
*/
|
||||
ValueNumber valueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr) or
|
||||
exists(FunctionIR funcIR |
|
||||
uniqueValueNumber(instr, funcIR) and
|
||||
result = TUniqueValueNumber(funcIR, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
|
||||
* value number.
|
||||
*/
|
||||
private ValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = instr.getFunctionIR() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, funcIR, var) and
|
||||
result = TVariableAddressValueNumber(funcIR, var)
|
||||
) or
|
||||
exists(IRVariable var |
|
||||
initializeParameterValueNumber(instr, funcIR, var) and
|
||||
result = TInitializeParameterValueNumber(funcIR, var)
|
||||
) or
|
||||
(
|
||||
initializeThisValueNumber(instr, funcIR) and
|
||||
result = TInitializeThisValueNumber(funcIR)
|
||||
) or
|
||||
exists(Type type, string value |
|
||||
constantValueNumber(instr, funcIR, type, value) and
|
||||
result = TConstantValueNumber(funcIR, type, value)
|
||||
) or
|
||||
exists(Field field, ValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, funcIR, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(funcIR, field, objectAddress)
|
||||
) or
|
||||
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
binaryValueNumber(instr, funcIR, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(funcIR, opcode, type, leftOperand, rightOperand)
|
||||
) or
|
||||
exists(Opcode opcode, Type type, ValueNumber operand |
|
||||
unaryValueNumber(instr, funcIR, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(funcIR, opcode, type, operand)
|
||||
) or
|
||||
exists(Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand |
|
||||
inheritanceConversionValueNumber(instr, funcIR, opcode, baseClass, derivedClass,
|
||||
operand) and
|
||||
result = TInheritanceConversionValueNumber(funcIR, opcode, baseClass, derivedClass, operand)
|
||||
) or
|
||||
exists(Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, funcIR, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(funcIR, opcode, type, elementSize, leftOperand,
|
||||
rightOperand)
|
||||
) or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.implementation.raw.IR as IR
|
||||
@@ -4,6 +4,7 @@ import IRBlockConstruction as BlockConstruction
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import TranslatedFunction
|
||||
|
||||
class InstructionTagType extends TInstructionTag {
|
||||
@@ -73,6 +74,13 @@ cached private module Cached {
|
||||
none()
|
||||
}
|
||||
|
||||
cached Expr getInstructionResultExpression(Instruction instruction) {
|
||||
exists(TranslatedExpr translatedExpr |
|
||||
translatedExpr = getTranslatedExpr(result) and
|
||||
instruction = translatedExpr.getResult()
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionOperand(
|
||||
instruction.getTag(), tag)
|
||||
|
||||
@@ -5,3 +5,30 @@ import IRVariable
|
||||
import OperandTag
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
|
||||
private newtype TIRPropertyProvider = MkIRPropertyProvider()
|
||||
|
||||
/**
|
||||
* Class that provides additional properties to be dumped for IR instructions and blocks when using
|
||||
* the PrintIR module. Libraries that compute additional facts about IR elements can extend the
|
||||
* single instance of this class to specify the additional properties computed by the library.
|
||||
*/
|
||||
class IRPropertyProvider extends TIRPropertyProvider {
|
||||
string toString() {
|
||||
result = "IRPropertyProvider"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified instruction.
|
||||
*/
|
||||
string getInstructionProperty(Instruction instruction, string key) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the property named `key` for the specified block.
|
||||
*/
|
||||
string getBlockProperty(IRBlock block, string key) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,14 @@ module InstructionSanity {
|
||||
operand = op.getOperand(tag) and
|
||||
operand.getFunctionIR() != op.getFunctionIR()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,6 +309,13 @@ class Instruction extends Construction::TInstruction {
|
||||
result = ast.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Expr` whose results is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getResultExpression() {
|
||||
result = Construction::getInstructionResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
* instruction does not produce a result, its result type will be `VoidType`.
|
||||
@@ -554,6 +569,15 @@ class InitializeParameterInstruction extends VariableInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes the `this` pointer parameter of the enclosing function.
|
||||
*/
|
||||
class InitializeThisInstruction extends Instruction {
|
||||
InitializeThisInstruction() {
|
||||
opcode instanceof Opcode::InitializeThis
|
||||
}
|
||||
}
|
||||
|
||||
class FieldAddressInstruction extends FieldInstruction {
|
||||
FieldAddressInstruction() {
|
||||
opcode instanceof Opcode::FieldAddress
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
private import IR
|
||||
import cpp
|
||||
|
||||
private string getAdditionalInstructionProperty(Instruction instr, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getInstructionProperty(instr, key)
|
||||
)
|
||||
}
|
||||
|
||||
private string getAdditionalBlockProperty(IRBlock block, string key) {
|
||||
exists(IRPropertyProvider provider |
|
||||
result = provider.getBlockProperty(block, key)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableFunctionIR(FunctionIR funcIR) or
|
||||
TPrintableIRBlock(IRBlock block) or
|
||||
@@ -135,6 +147,11 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||
result.getFunctionIR() = block.getFunctionIR()
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = PrintableIRNode.super.getProperty(key) or
|
||||
result = getAdditionalBlockProperty(block, key)
|
||||
}
|
||||
|
||||
final IRBlock getBlock() {
|
||||
result = block
|
||||
}
|
||||
@@ -185,6 +202,11 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||
final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
|
||||
override string getProperty(string key) {
|
||||
result = PrintableIRNode.super.getProperty(key) or
|
||||
result = getAdditionalInstructionProperty(instr, key)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate columnWidths(IRBlock block, int resultWidth, int operationWidth) {
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
private import internal.ValueNumberingInternal
|
||||
import cpp
|
||||
private import IR
|
||||
|
||||
/**
|
||||
* Provides additional information about value numbering in IR dumps.
|
||||
*/
|
||||
class ValueNumberPropertyProvider extends IRPropertyProvider {
|
||||
override string getInstructionProperty(Instruction instr, string key) {
|
||||
exists(ValueNumber vn |
|
||||
vn = valueNumber(instr) and
|
||||
key = "valnum" and
|
||||
if strictcount(vn.getAnInstruction()) > 1 then
|
||||
result = vn.toString()
|
||||
else
|
||||
result = "unique"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
newtype TValueNumber =
|
||||
TVariableAddressValueNumber(FunctionIR funcIR, IRVariable var) {
|
||||
variableAddressValueNumber(_, funcIR, var)
|
||||
} or
|
||||
TInitializeParameterValueNumber(FunctionIR funcIR, IRVariable var) {
|
||||
initializeParameterValueNumber(_, funcIR, var)
|
||||
} or
|
||||
TInitializeThisValueNumber(FunctionIR funcIR) {
|
||||
initializeThisValueNumber(_, funcIR)
|
||||
} or
|
||||
TConstantValueNumber(FunctionIR funcIR, Type type, string value) {
|
||||
constantValueNumber(_, funcIR, type, value)
|
||||
} or
|
||||
TFieldAddressValueNumber(FunctionIR funcIR, Field field, ValueNumber objectAddress) {
|
||||
fieldAddressValueNumber(_, funcIR, field, objectAddress)
|
||||
} or
|
||||
TBinaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand) {
|
||||
binaryValueNumber(_, funcIR, opcode, type, leftOperand, rightOperand)
|
||||
} or
|
||||
TPointerArithmeticValueNumber(FunctionIR funcIR, Opcode opcode, Type type, int elementSize,
|
||||
ValueNumber leftOperand, ValueNumber rightOperand) {
|
||||
pointerArithmeticValueNumber(_, funcIR, opcode, type, elementSize, leftOperand, rightOperand)
|
||||
} or
|
||||
TUnaryValueNumber(FunctionIR funcIR, Opcode opcode, Type type, ValueNumber operand) {
|
||||
unaryValueNumber(_, funcIR, opcode, type, operand)
|
||||
} or
|
||||
TInheritanceConversionValueNumber(FunctionIR funcIR, Opcode opcode, Class baseClass,
|
||||
Class derivedClass, ValueNumber operand) {
|
||||
inheritanceConversionValueNumber(_, funcIR, opcode, baseClass, derivedClass, operand)
|
||||
} or
|
||||
TUniqueValueNumber(FunctionIR funcIR, Instruction instr) {
|
||||
uniqueValueNumber(instr, funcIR)
|
||||
}
|
||||
|
||||
/**
|
||||
* The value number assigned to a particular set of instructions that produce equivalent results.
|
||||
*/
|
||||
class ValueNumber extends TValueNumber {
|
||||
final string toString() {
|
||||
result = getExampleInstruction().getResultId()
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
result = getExampleInstruction().getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instructions that have been assigned this value number. This will always produce at
|
||||
* least one result.
|
||||
*/
|
||||
final Instruction getAnInstruction() {
|
||||
this = valueNumber(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one of the instructions that was assigned this value number. The chosen instuction is
|
||||
* deterministic but arbitrary. Intended for use only in debugging.
|
||||
*/
|
||||
final Instruction getExampleInstruction() {
|
||||
result = min(Instruction instr |
|
||||
instr = getAnInstruction() |
|
||||
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||
* operand.
|
||||
* For example:
|
||||
* ```
|
||||
* Point p = { 1, 2 };
|
||||
* Point q = p;
|
||||
* int a = p.x;
|
||||
* ```
|
||||
* The use of `p` on line 2 is linked to the definition of `p` on line 1, and is congruent to that
|
||||
* definition because it accesses the exact same memory.
|
||||
* The use of `p.x` on line 3 is linked to the definition of `p` on line 1 as well, but is not
|
||||
* congruent to that definition because `p.x` accesses only a subset of the memory defined by `p`.
|
||||
*
|
||||
* This concept should probably be exposed in the public IR API.
|
||||
*/
|
||||
private class CongruentCopyInstruction extends CopyInstruction {
|
||||
CongruentCopyInstruction() {
|
||||
exists(Instruction def |
|
||||
def = this.getSourceValue() and
|
||||
(
|
||||
def.getResultMemoryAccess() instanceof IndirectMemoryAccess or
|
||||
not def.hasMemoryResult()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this library knows how to assign a value number to the specified instruction, other than
|
||||
* a `unique` value number that is never shared by multiple instructions.
|
||||
*/
|
||||
private predicate numberableInstruction(Instruction instr) {
|
||||
instr instanceof VariableAddressInstruction or
|
||||
instr instanceof InitializeParameterInstruction or
|
||||
instr instanceof InitializeThisInstruction or
|
||||
instr instanceof ConstantInstruction or
|
||||
instr instanceof FieldAddressInstruction or
|
||||
instr instanceof BinaryInstruction or
|
||||
instr instanceof UnaryInstruction or
|
||||
instr instanceof PointerArithmeticInstruction or
|
||||
instr instanceof CongruentCopyInstruction
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(VariableAddressInstruction instr, FunctionIR funcIR,
|
||||
IRVariable var) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeParameterValueNumber(InitializeParameterInstruction instr,
|
||||
FunctionIR funcIR, IRVariable var) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getVariable() = var
|
||||
}
|
||||
|
||||
private predicate initializeThisValueNumber(InitializeThisInstruction instr, FunctionIR funcIR) {
|
||||
instr.getFunctionIR() = funcIR
|
||||
}
|
||||
|
||||
private predicate constantValueNumber(ConstantInstruction instr, FunctionIR funcIR, Type type,
|
||||
string value) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getResultType() = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
|
||||
private predicate fieldAddressValueNumber(FieldAddressInstruction instr, FunctionIR funcIR,
|
||||
Field field, ValueNumber objectAddress) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getField() = field and
|
||||
valueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
|
||||
private predicate binaryValueNumber(BinaryInstruction instr, FunctionIR funcIR, Opcode opcode,
|
||||
Type type, ValueNumber leftOperand, ValueNumber rightOperand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
(not instr instanceof PointerArithmeticInstruction) and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
valueNumber(instr.getLeftOperand()) = leftOperand and
|
||||
valueNumber(instr.getRightOperand()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate pointerArithmeticValueNumber(PointerArithmeticInstruction instr,
|
||||
FunctionIR funcIR, Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
instr.getElementSize() = elementSize and
|
||||
valueNumber(instr.getLeftOperand()) = leftOperand and
|
||||
valueNumber(instr.getRightOperand()) = rightOperand
|
||||
}
|
||||
|
||||
private predicate unaryValueNumber(UnaryInstruction instr, FunctionIR funcIR, Opcode opcode,
|
||||
Type type, ValueNumber operand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
(not instr instanceof InheritanceConversionInstruction) and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getResultType() = type and
|
||||
valueNumber(instr.getOperand()) = operand
|
||||
}
|
||||
|
||||
private predicate inheritanceConversionValueNumber(InheritanceConversionInstruction instr,
|
||||
FunctionIR funcIR, Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getBaseClass() = baseClass and
|
||||
instr.getDerivedClass() = derivedClass and
|
||||
valueNumber(instr.getOperand()) = operand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr, FunctionIR funcIR) {
|
||||
instr.getFunctionIR() = funcIR and
|
||||
(not instr.getResultType() instanceof VoidType) and
|
||||
not numberableInstruction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any. Returns at most one result.
|
||||
*/
|
||||
ValueNumber valueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr) or
|
||||
exists(FunctionIR funcIR |
|
||||
uniqueValueNumber(instr, funcIR) and
|
||||
result = TUniqueValueNumber(funcIR, instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value number assigned to `instr`, if any, unless that instruction is assigned a unique
|
||||
* value number.
|
||||
*/
|
||||
private ValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(FunctionIR funcIR |
|
||||
funcIR = instr.getFunctionIR() and
|
||||
(
|
||||
exists(IRVariable var |
|
||||
variableAddressValueNumber(instr, funcIR, var) and
|
||||
result = TVariableAddressValueNumber(funcIR, var)
|
||||
) or
|
||||
exists(IRVariable var |
|
||||
initializeParameterValueNumber(instr, funcIR, var) and
|
||||
result = TInitializeParameterValueNumber(funcIR, var)
|
||||
) or
|
||||
(
|
||||
initializeThisValueNumber(instr, funcIR) and
|
||||
result = TInitializeThisValueNumber(funcIR)
|
||||
) or
|
||||
exists(Type type, string value |
|
||||
constantValueNumber(instr, funcIR, type, value) and
|
||||
result = TConstantValueNumber(funcIR, type, value)
|
||||
) or
|
||||
exists(Field field, ValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, funcIR, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(funcIR, field, objectAddress)
|
||||
) or
|
||||
exists(Opcode opcode, Type type, ValueNumber leftOperand, ValueNumber rightOperand |
|
||||
binaryValueNumber(instr, funcIR, opcode, type, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(funcIR, opcode, type, leftOperand, rightOperand)
|
||||
) or
|
||||
exists(Opcode opcode, Type type, ValueNumber operand |
|
||||
unaryValueNumber(instr, funcIR, opcode, type, operand) and
|
||||
result = TUnaryValueNumber(funcIR, opcode, type, operand)
|
||||
) or
|
||||
exists(Opcode opcode, Class baseClass, Class derivedClass, ValueNumber operand |
|
||||
inheritanceConversionValueNumber(instr, funcIR, opcode, baseClass, derivedClass,
|
||||
operand) and
|
||||
result = TInheritanceConversionValueNumber(funcIR, opcode, baseClass, derivedClass, operand)
|
||||
) or
|
||||
exists(Opcode opcode, Type type, int elementSize, ValueNumber leftOperand,
|
||||
ValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, funcIR, opcode, type, elementSize, leftOperand,
|
||||
rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(funcIR, opcode, type, elementSize, leftOperand,
|
||||
rightOperand)
|
||||
) or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = valueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR
|
||||
@@ -30,7 +30,9 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
cached newtype TInstructionTag =
|
||||
WrappedInstructionTag(OldIR::Instruction oldInstruction) or
|
||||
WrappedInstructionTag(OldIR::Instruction oldInstruction) {
|
||||
not oldInstruction instanceof OldIR::PhiInstruction
|
||||
} or
|
||||
PhiTag(Alias::VirtualVariable vvar, OldIR::IRBlock block) {
|
||||
hasPhiNode(vvar, block)
|
||||
}
|
||||
@@ -195,6 +197,10 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Expr getInstructionResultExpression(Instruction instruction) {
|
||||
result = getOldInstruction(instruction).getResultExpression()
|
||||
}
|
||||
|
||||
cached Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result = getNewInstruction(getOldInstruction(instruction).getSuccessor(kind))
|
||||
}
|
||||
|
||||
1095
cpp/ql/src/semmle/code/cpp/valuenumbering/HashCons.qll
Normal file
1095
cpp/ql/src/semmle/code/cpp/valuenumbering/HashCons.qll
Normal file
File diff suppressed because it is too large
Load Diff
@@ -5,3 +5,4 @@ missingPhiOperand
|
||||
instructionWithoutSuccessor
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
|
||||
@@ -5,3 +5,4 @@ missingPhiOperand
|
||||
instructionWithoutSuccessor
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
|
||||
@@ -5,3 +5,4 @@ missingPhiOperand
|
||||
instructionWithoutSuccessor
|
||||
unnecessaryPhiInstruction
|
||||
operandAcrossFunctions
|
||||
instructionWithoutUniqueBlock
|
||||
|
||||
@@ -27,3 +27,6 @@
|
||||
| test.cpp:62:5:62:10 | result | 62:c5-c10 65:c10-c15 |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | 77:c20-c30 79:c7-c7 |
|
||||
| test.cpp:79:11:79:14 | vals | 79:c11-c14 79:c24-c27 |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | 105:c11-c12 106:c14-c35 107:c11-c12 |
|
||||
| test.cpp:105:11:105:12 | pd | 105:c11-c12 106:c33-c34 |
|
||||
| test.cpp:105:15:105:15 | b | 105:c15-c15 107:c15-c15 109:c10-c10 |
|
||||
|
||||
@@ -0,0 +1,714 @@
|
||||
test.cpp:
|
||||
# 1| test00(int, int) -> int
|
||||
# 1| Block 0
|
||||
# 1| v0_0(void) = EnterFunction :
|
||||
# 1| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 1| valnum = unique
|
||||
# 1| r0_2(glval<int>) = VariableAddress[p0] :
|
||||
# 1| valnum = r0_2
|
||||
# 1| m0_3(int) = InitializeParameter[p0] : r0_2
|
||||
# 1| valnum = m0_3
|
||||
# 1| r0_4(glval<int>) = VariableAddress[p1] :
|
||||
# 1| valnum = r0_4
|
||||
# 1| m0_5(int) = InitializeParameter[p1] : r0_4
|
||||
# 1| valnum = m0_5
|
||||
# 2| r0_6(glval<int>) = VariableAddress[x] :
|
||||
# 2| valnum = r0_6
|
||||
# 2| m0_7(int) = Uninitialized : r0_6
|
||||
# 2| valnum = unique
|
||||
# 2| r0_8(glval<int>) = VariableAddress[y] :
|
||||
# 2| valnum = r0_8
|
||||
# 2| m0_9(int) = Uninitialized : r0_8
|
||||
# 2| valnum = unique
|
||||
# 3| r0_10(glval<unsigned char>) = VariableAddress[b] :
|
||||
# 3| valnum = unique
|
||||
# 3| m0_11(unsigned char) = Uninitialized : r0_10
|
||||
# 3| valnum = unique
|
||||
# 5| r0_12(glval<int>) = VariableAddress[p0] :
|
||||
# 5| valnum = r0_2
|
||||
# 5| r0_13(int) = Load : r0_12, m0_3
|
||||
# 5| valnum = m0_3
|
||||
# 5| r0_14(glval<int>) = VariableAddress[p1] :
|
||||
# 5| valnum = r0_4
|
||||
# 5| r0_15(int) = Load : r0_14, m0_5
|
||||
# 5| valnum = m0_5
|
||||
# 5| r0_16(int) = Add : r0_13, r0_15
|
||||
# 5| valnum = r0_16
|
||||
# 5| r0_17(glval<int>) = VariableAddress[x] :
|
||||
# 5| valnum = r0_6
|
||||
# 5| m0_18(int) = Store : r0_17, r0_16
|
||||
# 5| valnum = r0_16
|
||||
# 6| r0_19(glval<int>) = VariableAddress[p0] :
|
||||
# 6| valnum = r0_2
|
||||
# 6| r0_20(int) = Load : r0_19, m0_3
|
||||
# 6| valnum = m0_3
|
||||
# 6| r0_21(glval<int>) = VariableAddress[p1] :
|
||||
# 6| valnum = r0_4
|
||||
# 6| r0_22(int) = Load : r0_21, m0_5
|
||||
# 6| valnum = m0_5
|
||||
# 6| r0_23(int) = Add : r0_20, r0_22
|
||||
# 6| valnum = r0_16
|
||||
# 6| r0_24(glval<int>) = VariableAddress[x] :
|
||||
# 6| valnum = r0_6
|
||||
# 6| m0_25(int) = Store : r0_24, r0_23
|
||||
# 6| valnum = r0_16
|
||||
# 7| r0_26(glval<int>) = VariableAddress[x] :
|
||||
# 7| valnum = r0_6
|
||||
# 7| r0_27(int) = Load : r0_26, m0_25
|
||||
# 7| valnum = r0_16
|
||||
# 7| r0_28(glval<int>) = VariableAddress[y] :
|
||||
# 7| valnum = r0_8
|
||||
# 7| m0_29(int) = Store : r0_28, r0_27
|
||||
# 7| valnum = r0_16
|
||||
# 8| v0_30(void) = NoOp :
|
||||
# 1| r0_31(glval<int>) = VariableAddress[#return] :
|
||||
# 1| valnum = unique
|
||||
# 1| v0_32(void) = ReturnValue : r0_31
|
||||
# 1| v0_33(void) = UnmodeledUse : mu*
|
||||
# 1| v0_34(void) = ExitFunction :
|
||||
|
||||
# 12| test01(int, int) -> int
|
||||
# 12| Block 0
|
||||
# 12| v0_0(void) = EnterFunction :
|
||||
# 12| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 12| valnum = unique
|
||||
# 12| r0_2(glval<int>) = VariableAddress[p0] :
|
||||
# 12| valnum = r0_2
|
||||
# 12| m0_3(int) = InitializeParameter[p0] : r0_2
|
||||
# 12| valnum = m0_3
|
||||
# 12| r0_4(glval<int>) = VariableAddress[p1] :
|
||||
# 12| valnum = r0_4
|
||||
# 12| m0_5(int) = InitializeParameter[p1] : r0_4
|
||||
# 12| valnum = m0_5
|
||||
# 13| r0_6(glval<int>) = VariableAddress[x] :
|
||||
# 13| valnum = r0_6
|
||||
# 13| m0_7(int) = Uninitialized : r0_6
|
||||
# 13| valnum = unique
|
||||
# 13| r0_8(glval<int>) = VariableAddress[y] :
|
||||
# 13| valnum = r0_8
|
||||
# 13| m0_9(int) = Uninitialized : r0_8
|
||||
# 13| valnum = unique
|
||||
# 14| r0_10(glval<unsigned char>) = VariableAddress[b] :
|
||||
# 14| valnum = unique
|
||||
# 14| m0_11(unsigned char) = Uninitialized : r0_10
|
||||
# 14| valnum = unique
|
||||
# 16| r0_12(glval<int>) = VariableAddress[p0] :
|
||||
# 16| valnum = r0_2
|
||||
# 16| r0_13(int) = Load : r0_12, m0_3
|
||||
# 16| valnum = m0_3
|
||||
# 16| r0_14(glval<int>) = VariableAddress[p1] :
|
||||
# 16| valnum = r0_4
|
||||
# 16| r0_15(int) = Load : r0_14, m0_5
|
||||
# 16| valnum = m0_5
|
||||
# 16| r0_16(int) = Add : r0_13, r0_15
|
||||
# 16| valnum = r0_16
|
||||
# 16| r0_17(glval<int>) = VariableAddress[global01] :
|
||||
# 16| valnum = r0_17
|
||||
# 16| r0_18(int) = Load : r0_17, mu0_1
|
||||
# 16| valnum = unique
|
||||
# 16| r0_19(int) = Add : r0_16, r0_18
|
||||
# 16| valnum = r0_19
|
||||
# 16| r0_20(glval<int>) = VariableAddress[x] :
|
||||
# 16| valnum = r0_6
|
||||
# 16| m0_21(int) = Store : r0_20, r0_19
|
||||
# 16| valnum = r0_19
|
||||
# 17| r0_22(glval<int>) = VariableAddress[p0] :
|
||||
# 17| valnum = r0_2
|
||||
# 17| r0_23(int) = Load : r0_22, m0_3
|
||||
# 17| valnum = m0_3
|
||||
# 17| r0_24(glval<int>) = VariableAddress[p1] :
|
||||
# 17| valnum = r0_4
|
||||
# 17| r0_25(int) = Load : r0_24, m0_5
|
||||
# 17| valnum = m0_5
|
||||
# 17| r0_26(int) = Add : r0_23, r0_25
|
||||
# 17| valnum = r0_16
|
||||
# 17| r0_27(glval<int>) = VariableAddress[global01] :
|
||||
# 17| valnum = r0_17
|
||||
# 17| r0_28(int) = Load : r0_27, mu0_1
|
||||
# 17| valnum = unique
|
||||
# 17| r0_29(int) = Add : r0_26, r0_28
|
||||
# 17| valnum = r0_29
|
||||
# 17| r0_30(glval<int>) = VariableAddress[x] :
|
||||
# 17| valnum = r0_6
|
||||
# 17| m0_31(int) = Store : r0_30, r0_29
|
||||
# 17| valnum = r0_29
|
||||
# 18| r0_32(glval<int>) = VariableAddress[x] :
|
||||
# 18| valnum = r0_6
|
||||
# 18| r0_33(int) = Load : r0_32, m0_31
|
||||
# 18| valnum = r0_29
|
||||
# 18| r0_34(glval<int>) = VariableAddress[y] :
|
||||
# 18| valnum = r0_8
|
||||
# 18| m0_35(int) = Store : r0_34, r0_33
|
||||
# 18| valnum = r0_29
|
||||
# 19| v0_36(void) = NoOp :
|
||||
# 12| r0_37(glval<int>) = VariableAddress[#return] :
|
||||
# 12| valnum = unique
|
||||
# 12| v0_38(void) = ReturnValue : r0_37
|
||||
# 12| v0_39(void) = UnmodeledUse : mu*
|
||||
# 12| v0_40(void) = ExitFunction :
|
||||
|
||||
# 25| test02(int, int) -> int
|
||||
# 25| Block 0
|
||||
# 25| v0_0(void) = EnterFunction :
|
||||
# 25| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 25| valnum = unique
|
||||
# 25| r0_2(glval<int>) = VariableAddress[p0] :
|
||||
# 25| valnum = r0_2
|
||||
# 25| m0_3(int) = InitializeParameter[p0] : r0_2
|
||||
# 25| valnum = m0_3
|
||||
# 25| r0_4(glval<int>) = VariableAddress[p1] :
|
||||
# 25| valnum = r0_4
|
||||
# 25| m0_5(int) = InitializeParameter[p1] : r0_4
|
||||
# 25| valnum = m0_5
|
||||
# 26| r0_6(glval<int>) = VariableAddress[x] :
|
||||
# 26| valnum = r0_6
|
||||
# 26| m0_7(int) = Uninitialized : r0_6
|
||||
# 26| valnum = unique
|
||||
# 26| r0_8(glval<int>) = VariableAddress[y] :
|
||||
# 26| valnum = r0_8
|
||||
# 26| m0_9(int) = Uninitialized : r0_8
|
||||
# 26| valnum = unique
|
||||
# 27| r0_10(glval<unsigned char>) = VariableAddress[b] :
|
||||
# 27| valnum = unique
|
||||
# 27| m0_11(unsigned char) = Uninitialized : r0_10
|
||||
# 27| valnum = unique
|
||||
# 29| r0_12(glval<int>) = VariableAddress[p0] :
|
||||
# 29| valnum = r0_2
|
||||
# 29| r0_13(int) = Load : r0_12, m0_3
|
||||
# 29| valnum = m0_3
|
||||
# 29| r0_14(glval<int>) = VariableAddress[p1] :
|
||||
# 29| valnum = r0_4
|
||||
# 29| r0_15(int) = Load : r0_14, m0_5
|
||||
# 29| valnum = m0_5
|
||||
# 29| r0_16(int) = Add : r0_13, r0_15
|
||||
# 29| valnum = r0_16
|
||||
# 29| r0_17(glval<int>) = VariableAddress[global02] :
|
||||
# 29| valnum = r0_17
|
||||
# 29| r0_18(int) = Load : r0_17, mu0_1
|
||||
# 29| valnum = unique
|
||||
# 29| r0_19(int) = Add : r0_16, r0_18
|
||||
# 29| valnum = r0_19
|
||||
# 29| r0_20(glval<int>) = VariableAddress[x] :
|
||||
# 29| valnum = r0_6
|
||||
# 29| m0_21(int) = Store : r0_20, r0_19
|
||||
# 29| valnum = r0_19
|
||||
# 30| r0_22(glval<unknown>) = FunctionAddress[change_global02] :
|
||||
# 30| valnum = unique
|
||||
# 30| v0_23(void) = Call : r0_22
|
||||
# 31| r0_24(glval<int>) = VariableAddress[p0] :
|
||||
# 31| valnum = r0_2
|
||||
# 31| r0_25(int) = Load : r0_24, m0_3
|
||||
# 31| valnum = m0_3
|
||||
# 31| r0_26(glval<int>) = VariableAddress[p1] :
|
||||
# 31| valnum = r0_4
|
||||
# 31| r0_27(int) = Load : r0_26, m0_5
|
||||
# 31| valnum = m0_5
|
||||
# 31| r0_28(int) = Add : r0_25, r0_27
|
||||
# 31| valnum = r0_16
|
||||
# 31| r0_29(glval<int>) = VariableAddress[global02] :
|
||||
# 31| valnum = r0_17
|
||||
# 31| r0_30(int) = Load : r0_29, mu0_1
|
||||
# 31| valnum = unique
|
||||
# 31| r0_31(int) = Add : r0_28, r0_30
|
||||
# 31| valnum = r0_31
|
||||
# 31| r0_32(glval<int>) = VariableAddress[x] :
|
||||
# 31| valnum = r0_6
|
||||
# 31| m0_33(int) = Store : r0_32, r0_31
|
||||
# 31| valnum = r0_31
|
||||
# 32| r0_34(glval<int>) = VariableAddress[x] :
|
||||
# 32| valnum = r0_6
|
||||
# 32| r0_35(int) = Load : r0_34, m0_33
|
||||
# 32| valnum = r0_31
|
||||
# 32| r0_36(glval<int>) = VariableAddress[y] :
|
||||
# 32| valnum = r0_8
|
||||
# 32| m0_37(int) = Store : r0_36, r0_35
|
||||
# 32| valnum = r0_31
|
||||
# 33| v0_38(void) = NoOp :
|
||||
# 25| r0_39(glval<int>) = VariableAddress[#return] :
|
||||
# 25| valnum = unique
|
||||
# 25| v0_40(void) = ReturnValue : r0_39
|
||||
# 25| v0_41(void) = UnmodeledUse : mu*
|
||||
# 25| v0_42(void) = ExitFunction :
|
||||
|
||||
# 39| test03(int, int, int *) -> int
|
||||
# 39| Block 0
|
||||
# 39| v0_0(void) = EnterFunction :
|
||||
# 39| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 39| valnum = unique
|
||||
# 39| r0_2(glval<int>) = VariableAddress[p0] :
|
||||
# 39| valnum = r0_2
|
||||
# 39| m0_3(int) = InitializeParameter[p0] : r0_2
|
||||
# 39| valnum = m0_3
|
||||
# 39| r0_4(glval<int>) = VariableAddress[p1] :
|
||||
# 39| valnum = r0_4
|
||||
# 39| m0_5(int) = InitializeParameter[p1] : r0_4
|
||||
# 39| valnum = m0_5
|
||||
# 39| r0_6(glval<int *>) = VariableAddress[p2] :
|
||||
# 39| valnum = r0_6
|
||||
# 39| m0_7(int *) = InitializeParameter[p2] : r0_6
|
||||
# 39| valnum = m0_7
|
||||
# 40| r0_8(glval<int>) = VariableAddress[x] :
|
||||
# 40| valnum = r0_8
|
||||
# 40| m0_9(int) = Uninitialized : r0_8
|
||||
# 40| valnum = unique
|
||||
# 40| r0_10(glval<int>) = VariableAddress[y] :
|
||||
# 40| valnum = r0_10
|
||||
# 40| m0_11(int) = Uninitialized : r0_10
|
||||
# 40| valnum = unique
|
||||
# 41| r0_12(glval<unsigned char>) = VariableAddress[b] :
|
||||
# 41| valnum = unique
|
||||
# 41| m0_13(unsigned char) = Uninitialized : r0_12
|
||||
# 41| valnum = unique
|
||||
# 43| r0_14(glval<int>) = VariableAddress[p0] :
|
||||
# 43| valnum = r0_2
|
||||
# 43| r0_15(int) = Load : r0_14, m0_3
|
||||
# 43| valnum = m0_3
|
||||
# 43| r0_16(glval<int>) = VariableAddress[p1] :
|
||||
# 43| valnum = r0_4
|
||||
# 43| r0_17(int) = Load : r0_16, m0_5
|
||||
# 43| valnum = m0_5
|
||||
# 43| r0_18(int) = Add : r0_15, r0_17
|
||||
# 43| valnum = r0_18
|
||||
# 43| r0_19(glval<int>) = VariableAddress[global03] :
|
||||
# 43| valnum = r0_19
|
||||
# 43| r0_20(int) = Load : r0_19, mu0_1
|
||||
# 43| valnum = unique
|
||||
# 43| r0_21(int) = Add : r0_18, r0_20
|
||||
# 43| valnum = r0_21
|
||||
# 43| r0_22(glval<int>) = VariableAddress[x] :
|
||||
# 43| valnum = r0_8
|
||||
# 43| m0_23(int) = Store : r0_22, r0_21
|
||||
# 43| valnum = r0_21
|
||||
# 44| r0_24(int) = Constant[0] :
|
||||
# 44| valnum = r0_24
|
||||
# 44| r0_25(glval<int *>) = VariableAddress[p2] :
|
||||
# 44| valnum = r0_6
|
||||
# 44| r0_26(int *) = Load : r0_25, m0_7
|
||||
# 44| valnum = m0_7
|
||||
# 44| mu0_27(int) = Store : r0_26, r0_24
|
||||
# 44| valnum = r0_24
|
||||
# 45| r0_28(glval<int>) = VariableAddress[p0] :
|
||||
# 45| valnum = r0_2
|
||||
# 45| r0_29(int) = Load : r0_28, m0_3
|
||||
# 45| valnum = m0_3
|
||||
# 45| r0_30(glval<int>) = VariableAddress[p1] :
|
||||
# 45| valnum = r0_4
|
||||
# 45| r0_31(int) = Load : r0_30, m0_5
|
||||
# 45| valnum = m0_5
|
||||
# 45| r0_32(int) = Add : r0_29, r0_31
|
||||
# 45| valnum = r0_18
|
||||
# 45| r0_33(glval<int>) = VariableAddress[global03] :
|
||||
# 45| valnum = r0_19
|
||||
# 45| r0_34(int) = Load : r0_33, mu0_1
|
||||
# 45| valnum = unique
|
||||
# 45| r0_35(int) = Add : r0_32, r0_34
|
||||
# 45| valnum = r0_35
|
||||
# 45| r0_36(glval<int>) = VariableAddress[x] :
|
||||
# 45| valnum = r0_8
|
||||
# 45| m0_37(int) = Store : r0_36, r0_35
|
||||
# 45| valnum = r0_35
|
||||
# 46| r0_38(glval<int>) = VariableAddress[x] :
|
||||
# 46| valnum = r0_8
|
||||
# 46| r0_39(int) = Load : r0_38, m0_37
|
||||
# 46| valnum = r0_35
|
||||
# 46| r0_40(glval<int>) = VariableAddress[y] :
|
||||
# 46| valnum = r0_10
|
||||
# 46| m0_41(int) = Store : r0_40, r0_39
|
||||
# 46| valnum = r0_35
|
||||
# 47| v0_42(void) = NoOp :
|
||||
# 39| r0_43(glval<int>) = VariableAddress[#return] :
|
||||
# 39| valnum = unique
|
||||
# 39| v0_44(void) = ReturnValue : r0_43
|
||||
# 39| v0_45(void) = UnmodeledUse : mu*
|
||||
# 39| v0_46(void) = ExitFunction :
|
||||
|
||||
# 49| my_strspn(const char *, const char *) -> unsigned int
|
||||
# 49| Block 0
|
||||
# 49| v0_0(void) = EnterFunction :
|
||||
# 49| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 49| valnum = unique
|
||||
# 49| r0_2(glval<char *>) = VariableAddress[str] :
|
||||
# 49| valnum = r0_2
|
||||
# 49| m0_3(char *) = InitializeParameter[str] : r0_2
|
||||
# 49| valnum = m0_3
|
||||
# 49| r0_4(glval<char *>) = VariableAddress[chars] :
|
||||
# 49| valnum = r0_4
|
||||
# 49| m0_5(char *) = InitializeParameter[chars] : r0_4
|
||||
# 49| valnum = m0_5
|
||||
# 50| r0_6(glval<char *>) = VariableAddress[ptr] :
|
||||
# 50| valnum = r0_6
|
||||
# 50| m0_7(char *) = Uninitialized : r0_6
|
||||
# 50| valnum = unique
|
||||
# 51| r0_8(glval<unsigned int>) = VariableAddress[result] :
|
||||
# 51| valnum = r0_8
|
||||
# 51| r0_9(unsigned int) = Constant[0] :
|
||||
# 51| valnum = r0_9
|
||||
# 51| m0_10(unsigned int) = Store : r0_8, r0_9
|
||||
# 51| valnum = r0_9
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 53| Block 1
|
||||
# 53| m1_0(unsigned int) = Phi : from 0:m0_10, from 8:m8_4
|
||||
# 53| valnum = unique
|
||||
# 53| r1_1(glval<char *>) = VariableAddress[str] :
|
||||
# 53| valnum = r0_2
|
||||
# 53| r1_2(char *) = Load : r1_1, m0_3
|
||||
# 53| valnum = m0_3
|
||||
# 53| r1_3(char) = Load : r1_2, mu0_1
|
||||
# 53| valnum = unique
|
||||
# 53| r1_4(int) = Convert : r1_3
|
||||
# 53| valnum = unique
|
||||
# 53| r1_5(int) = Constant[0] :
|
||||
# 53| valnum = r1_5
|
||||
# 53| r1_6(bool) = CompareNE : r1_4, r1_5
|
||||
# 53| valnum = unique
|
||||
# 53| v1_7(void) = ConditionalBranch : r1_6
|
||||
#-----| False -> Block 9
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 55| Block 2
|
||||
# 55| r2_0(glval<char *>) = VariableAddress[chars] :
|
||||
# 55| valnum = r0_4
|
||||
# 55| r2_1(char *) = Load : r2_0, m0_5
|
||||
# 55| valnum = m0_5
|
||||
# 55| r2_2(glval<char *>) = VariableAddress[ptr] :
|
||||
# 55| valnum = r0_6
|
||||
# 55| m2_3(char *) = Store : r2_2, r2_1
|
||||
# 55| valnum = m0_5
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 56| Block 3
|
||||
# 56| m3_0(char *) = Phi : from 2:m2_3, from 5:m5_4
|
||||
# 56| valnum = unique
|
||||
# 56| r3_1(glval<char *>) = VariableAddress[ptr] :
|
||||
# 56| valnum = r0_6
|
||||
# 56| r3_2(char *) = Load : r3_1, m3_0
|
||||
# 56| valnum = unique
|
||||
# 56| r3_3(char) = Load : r3_2, mu0_1
|
||||
# 56| valnum = unique
|
||||
# 56| r3_4(int) = Convert : r3_3
|
||||
# 56| valnum = unique
|
||||
# 56| r3_5(glval<char *>) = VariableAddress[str] :
|
||||
# 56| valnum = r0_2
|
||||
# 56| r3_6(char *) = Load : r3_5, m0_3
|
||||
# 56| valnum = m0_3
|
||||
# 56| r3_7(char) = Load : r3_6, mu0_1
|
||||
# 56| valnum = unique
|
||||
# 56| r3_8(int) = Convert : r3_7
|
||||
# 56| valnum = unique
|
||||
# 56| r3_9(bool) = CompareNE : r3_4, r3_8
|
||||
# 56| valnum = unique
|
||||
# 56| v3_10(void) = ConditionalBranch : r3_9
|
||||
#-----| False -> Block 6
|
||||
#-----| True -> Block 4
|
||||
|
||||
# 56| Block 4
|
||||
# 56| r4_0(glval<char *>) = VariableAddress[ptr] :
|
||||
# 56| valnum = r0_6
|
||||
# 56| r4_1(char *) = Load : r4_0, m3_0
|
||||
# 56| valnum = unique
|
||||
# 56| r4_2(char) = Load : r4_1, mu0_1
|
||||
# 56| valnum = unique
|
||||
# 56| r4_3(int) = Convert : r4_2
|
||||
# 56| valnum = unique
|
||||
# 56| r4_4(int) = Constant[0] :
|
||||
# 56| valnum = r1_5
|
||||
# 56| r4_5(bool) = CompareNE : r4_3, r4_4
|
||||
# 56| valnum = unique
|
||||
# 56| v4_6(void) = ConditionalBranch : r4_5
|
||||
#-----| False -> Block 6
|
||||
#-----| True -> Block 5
|
||||
|
||||
# 56| Block 5
|
||||
# 56| r5_0(glval<char *>) = VariableAddress[ptr] :
|
||||
# 56| valnum = r0_6
|
||||
# 56| r5_1(char *) = Load : r5_0, m3_0
|
||||
# 56| valnum = unique
|
||||
# 56| r5_2(int) = Constant[1] :
|
||||
# 56| valnum = unique
|
||||
# 56| r5_3(char *) = PointerAdd[1] : r5_1, r5_2
|
||||
# 56| valnum = r5_3
|
||||
# 56| m5_4(char *) = Store : r5_0, r5_3
|
||||
# 56| valnum = r5_3
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 59| Block 6
|
||||
# 59| r6_0(glval<char *>) = VariableAddress[ptr] :
|
||||
# 59| valnum = r0_6
|
||||
# 59| r6_1(char *) = Load : r6_0, m3_0
|
||||
# 59| valnum = unique
|
||||
# 59| r6_2(char) = Load : r6_1, mu0_1
|
||||
# 59| valnum = unique
|
||||
# 59| r6_3(int) = Convert : r6_2
|
||||
# 59| valnum = unique
|
||||
# 59| r6_4(int) = Constant[0] :
|
||||
# 59| valnum = r1_5
|
||||
# 59| r6_5(bool) = CompareEQ : r6_3, r6_4
|
||||
# 59| valnum = unique
|
||||
# 59| v6_6(void) = ConditionalBranch : r6_5
|
||||
#-----| False -> Block 8
|
||||
#-----| True -> Block 7
|
||||
|
||||
# 60| Block 7
|
||||
# 60| v7_0(void) = NoOp :
|
||||
#-----| Goto -> Block 9
|
||||
|
||||
# 62| Block 8
|
||||
# 62| r8_0(glval<unsigned int>) = VariableAddress[result] :
|
||||
# 62| valnum = r0_8
|
||||
# 62| r8_1(unsigned int) = Load : r8_0, m1_0
|
||||
# 62| valnum = unique
|
||||
# 62| r8_2(unsigned int) = Constant[1] :
|
||||
# 62| valnum = unique
|
||||
# 62| r8_3(unsigned int) = Add : r8_1, r8_2
|
||||
# 62| valnum = r8_3
|
||||
# 62| m8_4(unsigned int) = Store : r8_0, r8_3
|
||||
# 62| valnum = r8_3
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 63| Block 9
|
||||
# 63| v9_0(void) = NoOp :
|
||||
# 65| r9_1(glval<unsigned int>) = VariableAddress[#return] :
|
||||
# 65| valnum = r9_1
|
||||
# 65| r9_2(glval<unsigned int>) = VariableAddress[result] :
|
||||
# 65| valnum = r0_8
|
||||
# 65| r9_3(unsigned int) = Load : r9_2, m1_0
|
||||
# 65| valnum = r9_3
|
||||
# 65| m9_4(unsigned int) = Store : r9_1, r9_3
|
||||
# 65| valnum = r9_3
|
||||
# 49| r9_5(glval<unsigned int>) = VariableAddress[#return] :
|
||||
# 49| valnum = r9_1
|
||||
# 49| v9_6(void) = ReturnValue : r9_5, m9_4
|
||||
# 49| v9_7(void) = UnmodeledUse : mu*
|
||||
# 49| v9_8(void) = ExitFunction :
|
||||
|
||||
# 75| test04(two_values *) -> void
|
||||
# 75| Block 0
|
||||
# 75| v0_0(void) = EnterFunction :
|
||||
# 75| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 75| valnum = unique
|
||||
# 75| r0_2(glval<two_values *>) = VariableAddress[vals] :
|
||||
# 75| valnum = r0_2
|
||||
# 75| m0_3(two_values *) = InitializeParameter[vals] : r0_2
|
||||
# 75| valnum = m0_3
|
||||
# 77| r0_4(glval<signed short>) = VariableAddress[v] :
|
||||
# 77| valnum = r0_4
|
||||
# 77| r0_5(glval<unknown>) = FunctionAddress[getAValue] :
|
||||
# 77| valnum = unique
|
||||
# 77| r0_6(int) = Call : r0_5
|
||||
# 77| valnum = unique
|
||||
# 77| r0_7(signed short) = Convert : r0_6
|
||||
# 77| valnum = r0_7
|
||||
# 77| m0_8(signed short) = Store : r0_4, r0_7
|
||||
# 77| valnum = r0_7
|
||||
# 79| r0_9(glval<signed short>) = VariableAddress[v] :
|
||||
# 79| valnum = r0_4
|
||||
# 79| r0_10(signed short) = Load : r0_9, m0_8
|
||||
# 79| valnum = r0_7
|
||||
# 79| r0_11(int) = Convert : r0_10
|
||||
# 79| valnum = unique
|
||||
# 79| r0_12(glval<two_values *>) = VariableAddress[vals] :
|
||||
# 79| valnum = r0_2
|
||||
# 79| r0_13(two_values *) = Load : r0_12, m0_3
|
||||
# 79| valnum = m0_3
|
||||
# 79| r0_14(glval<signed short>) = FieldAddress[val1] : r0_13
|
||||
# 79| valnum = unique
|
||||
# 79| r0_15(signed short) = Load : r0_14, mu0_1
|
||||
# 79| valnum = unique
|
||||
# 79| r0_16(int) = Convert : r0_15
|
||||
# 79| valnum = unique
|
||||
# 79| r0_17(glval<two_values *>) = VariableAddress[vals] :
|
||||
# 79| valnum = r0_2
|
||||
# 79| r0_18(two_values *) = Load : r0_17, m0_3
|
||||
# 79| valnum = m0_3
|
||||
# 79| r0_19(glval<signed short>) = FieldAddress[val2] : r0_18
|
||||
# 79| valnum = unique
|
||||
# 79| r0_20(signed short) = Load : r0_19, mu0_1
|
||||
# 79| valnum = unique
|
||||
# 79| r0_21(int) = Convert : r0_20
|
||||
# 79| valnum = unique
|
||||
# 79| r0_22(int) = Add : r0_16, r0_21
|
||||
# 79| valnum = unique
|
||||
# 79| r0_23(bool) = CompareLT : r0_11, r0_22
|
||||
# 79| valnum = unique
|
||||
# 79| v0_24(void) = ConditionalBranch : r0_23
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 80| Block 1
|
||||
# 80| r1_0(glval<unknown>) = FunctionAddress[getAValue] :
|
||||
# 80| valnum = unique
|
||||
# 80| r1_1(int) = Call : r1_0
|
||||
# 80| valnum = unique
|
||||
# 80| r1_2(signed short) = Convert : r1_1
|
||||
# 80| valnum = r1_2
|
||||
# 80| r1_3(glval<signed short>) = VariableAddress[v] :
|
||||
# 80| valnum = r0_4
|
||||
# 80| m1_4(signed short) = Store : r1_3, r1_2
|
||||
# 80| valnum = r1_2
|
||||
#-----| Goto -> Block 2
|
||||
|
||||
# 82| Block 2
|
||||
# 82| v2_0(void) = NoOp :
|
||||
# 75| v2_1(void) = ReturnVoid :
|
||||
# 75| v2_2(void) = UnmodeledUse : mu*
|
||||
# 75| v2_3(void) = ExitFunction :
|
||||
|
||||
# 84| test05(int, int, void *) -> void
|
||||
# 84| Block 0
|
||||
# 84| v0_0(void) = EnterFunction :
|
||||
# 84| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 84| valnum = unique
|
||||
# 84| r0_2(glval<int>) = VariableAddress[x] :
|
||||
# 84| valnum = r0_2
|
||||
# 84| m0_3(int) = InitializeParameter[x] : r0_2
|
||||
# 84| valnum = m0_3
|
||||
# 84| r0_4(glval<int>) = VariableAddress[y] :
|
||||
# 84| valnum = r0_4
|
||||
# 84| m0_5(int) = InitializeParameter[y] : r0_4
|
||||
# 84| valnum = m0_5
|
||||
# 84| r0_6(glval<void *>) = VariableAddress[p] :
|
||||
# 84| valnum = r0_6
|
||||
# 84| m0_7(void *) = InitializeParameter[p] : r0_6
|
||||
# 84| valnum = m0_7
|
||||
# 86| r0_8(glval<int>) = VariableAddress[v] :
|
||||
# 86| valnum = r0_8
|
||||
# 86| m0_9(int) = Uninitialized : r0_8
|
||||
# 86| valnum = unique
|
||||
# 88| r0_10(glval<void *>) = VariableAddress[p] :
|
||||
# 88| valnum = r0_6
|
||||
# 88| r0_11(void *) = Load : r0_10, m0_7
|
||||
# 88| valnum = m0_7
|
||||
# 88| r0_12(void *) = Constant[0] :
|
||||
# 88| valnum = unique
|
||||
# 88| r0_13(bool) = CompareNE : r0_11, r0_12
|
||||
# 88| valnum = unique
|
||||
# 88| v0_14(void) = ConditionalBranch : r0_13
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 88| Block 1
|
||||
# 88| r1_0(glval<int>) = VariableAddress[x] :
|
||||
# 88| valnum = r0_2
|
||||
# 88| r1_1(int) = Load : r1_0, m0_3
|
||||
# 88| valnum = m0_3
|
||||
# 88| r1_2(glval<int>) = VariableAddress[#temp88:7] :
|
||||
# 88| valnum = r1_2
|
||||
# 88| m1_3(int) = Store : r1_2, r1_1
|
||||
# 88| valnum = m0_3
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 88| Block 2
|
||||
# 88| r2_0(glval<int>) = VariableAddress[y] :
|
||||
# 88| valnum = r0_4
|
||||
# 88| r2_1(int) = Load : r2_0, m0_5
|
||||
# 88| valnum = m0_5
|
||||
# 88| r2_2(glval<int>) = VariableAddress[#temp88:7] :
|
||||
# 88| valnum = r1_2
|
||||
# 88| m2_3(int) = Store : r2_2, r2_1
|
||||
# 88| valnum = m0_5
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 88| Block 3
|
||||
# 88| m3_0(int) = Phi : from 1:m1_3, from 2:m2_3
|
||||
# 88| valnum = unique
|
||||
# 88| r3_1(glval<int>) = VariableAddress[#temp88:7] :
|
||||
# 88| valnum = r1_2
|
||||
# 88| r3_2(int) = Load : r3_1, m3_0
|
||||
# 88| valnum = r3_2
|
||||
# 88| r3_3(glval<int>) = VariableAddress[v] :
|
||||
# 88| valnum = r0_8
|
||||
# 88| m3_4(int) = Store : r3_3, r3_2
|
||||
# 88| valnum = r3_2
|
||||
# 89| v3_5(void) = NoOp :
|
||||
# 84| v3_6(void) = ReturnVoid :
|
||||
# 84| v3_7(void) = UnmodeledUse : mu*
|
||||
# 84| v3_8(void) = ExitFunction :
|
||||
|
||||
# 91| regression_test00() -> int
|
||||
# 91| Block 0
|
||||
# 91| v0_0(void) = EnterFunction :
|
||||
# 91| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 91| valnum = unique
|
||||
# 92| r0_2(glval<int>) = VariableAddress[x] :
|
||||
# 92| valnum = r0_2
|
||||
# 92| r0_3(int) = Constant[10] :
|
||||
# 92| valnum = r0_3
|
||||
# 92| r0_4(glval<int>) = VariableAddress[x] :
|
||||
# 92| valnum = r0_2
|
||||
# 92| m0_5(int) = Store : r0_4, r0_3
|
||||
# 92| valnum = r0_3
|
||||
# 92| m0_6(int) = Store : r0_2, r0_3
|
||||
# 92| valnum = r0_3
|
||||
# 93| r0_7(glval<int>) = VariableAddress[#return] :
|
||||
# 93| valnum = r0_7
|
||||
# 93| r0_8(glval<int>) = VariableAddress[x] :
|
||||
# 93| valnum = r0_2
|
||||
# 93| r0_9(int) = Load : r0_8, m0_6
|
||||
# 93| valnum = r0_3
|
||||
# 93| m0_10(int) = Store : r0_7, r0_9
|
||||
# 93| valnum = r0_3
|
||||
# 91| r0_11(glval<int>) = VariableAddress[#return] :
|
||||
# 91| valnum = r0_7
|
||||
# 91| v0_12(void) = ReturnValue : r0_11, m0_10
|
||||
# 91| v0_13(void) = UnmodeledUse : mu*
|
||||
# 91| v0_14(void) = ExitFunction :
|
||||
|
||||
# 104| inheritanceConversions(Derived *) -> int
|
||||
# 104| Block 0
|
||||
# 104| v0_0(void) = EnterFunction :
|
||||
# 104| mu0_1(unknown) = UnmodeledDefinition :
|
||||
# 104| valnum = unique
|
||||
# 104| r0_2(glval<Derived *>) = VariableAddress[pd] :
|
||||
# 104| valnum = r0_2
|
||||
# 104| m0_3(Derived *) = InitializeParameter[pd] : r0_2
|
||||
# 104| valnum = m0_3
|
||||
# 105| r0_4(glval<int>) = VariableAddress[x] :
|
||||
# 105| valnum = unique
|
||||
# 105| r0_5(glval<Derived *>) = VariableAddress[pd] :
|
||||
# 105| valnum = r0_2
|
||||
# 105| r0_6(Derived *) = Load : r0_5, m0_3
|
||||
# 105| valnum = m0_3
|
||||
# 105| r0_7(Base *) = ConvertToBase[Derived : Base] : r0_6
|
||||
# 105| valnum = r0_7
|
||||
# 105| r0_8(glval<int>) = FieldAddress[b] : r0_7
|
||||
# 105| valnum = r0_8
|
||||
# 105| r0_9(int) = Load : r0_8, mu0_1
|
||||
# 105| valnum = r0_9
|
||||
# 105| m0_10(int) = Store : r0_4, r0_9
|
||||
# 105| valnum = r0_9
|
||||
# 106| r0_11(glval<Base *>) = VariableAddress[pb] :
|
||||
# 106| valnum = r0_11
|
||||
# 106| r0_12(glval<Derived *>) = VariableAddress[pd] :
|
||||
# 106| valnum = r0_2
|
||||
# 106| r0_13(Derived *) = Load : r0_12, m0_3
|
||||
# 106| valnum = m0_3
|
||||
# 106| r0_14(Base *) = ConvertToBase[Derived : Base] : r0_13
|
||||
# 106| valnum = r0_7
|
||||
# 106| m0_15(Base *) = Store : r0_11, r0_14
|
||||
# 106| valnum = r0_7
|
||||
# 107| r0_16(glval<int>) = VariableAddress[y] :
|
||||
# 107| valnum = r0_16
|
||||
# 107| r0_17(glval<Base *>) = VariableAddress[pb] :
|
||||
# 107| valnum = r0_11
|
||||
# 107| r0_18(Base *) = Load : r0_17, m0_15
|
||||
# 107| valnum = r0_7
|
||||
# 107| r0_19(glval<int>) = FieldAddress[b] : r0_18
|
||||
# 107| valnum = r0_8
|
||||
# 107| r0_20(int) = Load : r0_19, mu0_1
|
||||
# 107| valnum = r0_20
|
||||
# 107| m0_21(int) = Store : r0_16, r0_20
|
||||
# 107| valnum = r0_20
|
||||
# 109| r0_22(glval<int>) = VariableAddress[#return] :
|
||||
# 109| valnum = r0_22
|
||||
# 109| r0_23(glval<int>) = VariableAddress[y] :
|
||||
# 109| valnum = r0_16
|
||||
# 109| r0_24(int) = Load : r0_23, m0_21
|
||||
# 109| valnum = r0_20
|
||||
# 109| m0_25(int) = Store : r0_22, r0_24
|
||||
# 109| valnum = r0_20
|
||||
# 104| r0_26(glval<int>) = VariableAddress[#return] :
|
||||
# 104| valnum = r0_22
|
||||
# 104| v0_27(void) = ReturnValue : r0_26, m0_25
|
||||
# 104| v0_28(void) = UnmodeledUse : mu*
|
||||
# 104| v0_29(void) = ExitFunction :
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* @kind graph
|
||||
*/
|
||||
import semmle.code.cpp.ir.PrintIR
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.ValueNumbering
|
||||
@@ -92,3 +92,19 @@ int regression_test00() {
|
||||
int x = x = 10;
|
||||
return x;
|
||||
}
|
||||
|
||||
struct Base {
|
||||
int b;
|
||||
};
|
||||
|
||||
struct Derived : Base {
|
||||
int d;
|
||||
};
|
||||
|
||||
int inheritanceConversions(Derived* pd) {
|
||||
int x = pd->b;
|
||||
Base* pb = static_cast<Base*>(pd);
|
||||
int y = pb->b;
|
||||
|
||||
return y;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
| test.cpp:5:3:5:3 | x | 5:c3-c3 6:c3-c3 7:c7-c7 |
|
||||
| test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 |
|
||||
| test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 |
|
||||
| test.cpp:5:12:5:13 | p1 | 5:c12-c13 6:c12-c13 |
|
||||
| test.cpp:16:3:16:3 | x | 16:c3-c3 17:c3-c3 18:c7-c7 |
|
||||
| test.cpp:16:7:16:8 | p0 | 16:c7-c8 17:c7-c8 |
|
||||
| test.cpp:16:7:16:13 | ... + ... | 16:c7-c13 17:c7-c13 |
|
||||
| test.cpp:16:7:16:24 | ... + ... | 16:c7-c24 17:c7-c24 |
|
||||
| test.cpp:16:12:16:13 | p1 | 16:c12-c13 17:c12-c13 |
|
||||
| test.cpp:16:17:16:24 | global01 | 16:c17-c24 17:c17-c24 |
|
||||
| test.cpp:29:3:29:3 | x | 29:c3-c3 31:c3-c3 32:c7-c7 |
|
||||
| test.cpp:29:7:29:8 | p0 | 29:c7-c8 31:c7-c8 |
|
||||
| test.cpp:29:7:29:13 | ... + ... | 29:c7-c13 31:c7-c13 |
|
||||
| test.cpp:29:7:29:24 | ... + ... | 29:c7-c24 31:c7-c24 |
|
||||
| test.cpp:29:12:29:13 | p1 | 29:c12-c13 31:c12-c13 |
|
||||
| test.cpp:29:17:29:24 | global02 | 29:c17-c24 31:c17-c24 |
|
||||
| test.cpp:43:3:43:3 | x | 43:c3-c3 45:c3-c3 46:c7-c7 |
|
||||
| test.cpp:43:7:43:8 | p0 | 43:c7-c8 45:c7-c8 |
|
||||
| test.cpp:43:7:43:13 | ... + ... | 43:c7-c13 45:c7-c13 |
|
||||
| test.cpp:43:7:43:24 | ... + ... | 43:c7-c24 45:c7-c24 |
|
||||
| test.cpp:43:12:43:13 | p1 | 43:c12-c13 45:c12-c13 |
|
||||
| test.cpp:43:17:43:24 | global03 | 43:c17-c24 45:c17-c24 |
|
||||
| test.cpp:53:10:53:13 | (int)... | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:10:53:13 | * ... | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:11:53:13 | str | 53:c11-c13 56:c22-c24 |
|
||||
| test.cpp:55:5:55:7 | ptr | 55:c5-c7 56:c14-c16 56:c32-c34 56:c47-c49 59:c10-c12 |
|
||||
| test.cpp:59:9:59:12 | (int)... | 56:c13-c16 56:c31-c34 59:c9-c12 |
|
||||
| test.cpp:59:9:59:12 | * ... | 56:c13-c16 56:c31-c34 59:c9-c12 |
|
||||
| test.cpp:59:17:59:20 | 0 | 53:c18-c21 56:c39-c42 59:c17-c20 |
|
||||
| test.cpp:59:17:59:20 | (int)... | 53:c18-c21 56:c39-c42 59:c17-c20 |
|
||||
| test.cpp:62:5:62:10 | result | 62:c5-c10 65:c10-c15 |
|
||||
| test.cpp:79:11:79:14 | vals | 79:c11-c14 79:c24-c27 |
|
||||
| test.cpp:80:5:80:5 | v | 79:c7-c7 80:c5-c5 |
|
||||
| test.cpp:80:9:80:17 | call to getAValue | 77:c20-c28 80:c9-c17 |
|
||||
| test.cpp:80:9:80:19 | (signed short)... | 77:c20-c30 80:c9-c19 |
|
||||
| test.cpp:92:15:92:16 | 10 | 260:c21-c22 261:c21-c22 92:c15-c16 |
|
||||
| test.cpp:93:10:93:10 | x | 92:c11-c11 93:c10-c10 |
|
||||
| test.cpp:97:3:97:3 | x | 97:c3-c3 98:c3-c3 |
|
||||
| test.cpp:97:3:97:5 | ... ++ | 97:c3-c5 98:c3-c5 |
|
||||
| test.cpp:104:3:104:3 | x | 104:c3-c3 105:c3-c3 106:c3-c3 107:c3-c3 108:c3-c3 |
|
||||
| test.cpp:107:7:107:11 | ... + ... | 107:c7-c11 108:c7-c11 |
|
||||
| test.cpp:111:3:111:5 | str | 111:c3-c5 112:c3-c5 113:c3-c5 |
|
||||
| test.cpp:111:9:111:11 | 1 | 110:c15-c17 111:c9-c11 |
|
||||
| test.cpp:111:9:111:11 | (char *)... | 110:c15-c17 111:c9-c11 |
|
||||
| test.cpp:111:9:111:11 | array to pointer conversion | 110:c15-c17 111:c9-c11 |
|
||||
| test.cpp:112:9:112:11 | 2 | 112:c9-c11 113:c9-c11 |
|
||||
| test.cpp:112:9:112:11 | (char *)... | 112:c9-c11 113:c9-c11 |
|
||||
| test.cpp:112:9:112:11 | array to pointer conversion | 112:c9-c11 113:c9-c11 |
|
||||
| test.cpp:116:3:116:3 | y | 116:c3-c3 117:c3-c3 118:c3-c3 |
|
||||
| test.cpp:116:7:116:9 | 0.0 | 115:c13-c15 116:c7-c9 |
|
||||
| test.cpp:116:7:116:9 | (float)... | 115:c13-c15 116:c7-c9 |
|
||||
| test.cpp:117:7:117:9 | 0.5 | 117:c7-c9 118:c7-c9 |
|
||||
| test.cpp:117:7:117:9 | (float)... | 117:c7-c9 118:c7-c9 |
|
||||
| test.cpp:122:3:122:8 | call to test07 | 122:c3-c8 123:c3-c8 |
|
||||
| test.cpp:125:3:125:11 | call to my_strspn | 125:c3-c11 126:c3-c11 |
|
||||
| test.cpp:125:13:125:17 | array to pointer conversion | 125:c13-c17 126:c13-c17 129:c20-c24 |
|
||||
| test.cpp:125:13:125:17 | foo | 125:c13-c17 126:c13-c17 129:c20-c24 |
|
||||
| test.cpp:129:13:129:17 | array to pointer conversion | 125:c20-c24 126:c20-c24 129:c13-c17 |
|
||||
| test.cpp:129:13:129:17 | bar | 125:c20-c24 126:c20-c24 129:c13-c17 |
|
||||
| test.cpp:141:12:141:17 | call to getInt | 141:c12-c17 141:c29-c34 |
|
||||
| test.cpp:141:23:141:26 | this | 0:c0-c0 141:c23-c26 |
|
||||
| test.cpp:146:10:146:11 | ih | 146:c10-c11 146:c31-c32 |
|
||||
| test.cpp:146:13:146:25 | call to getDoubledInt | 146:c13-c25 146:c34-c46 |
|
||||
| test.cpp:150:3:150:3 | x | 150:c3-c3 150:c9-c9 151:c3-c3 151:c9-c9 152:c12-c12 |
|
||||
| test.cpp:150:3:150:5 | ... ++ | 150:c3-c5 150:c9-c11 151:c3-c5 151:c9-c11 152:c10-c12 |
|
||||
| test.cpp:150:3:150:11 | ... + ... | 150:c3-c11 151:c3-c11 |
|
||||
| test.cpp:156:3:156:9 | 0 | 156:c14-c20 156:c3-c9 157:c10-c16 |
|
||||
| test.cpp:171:3:171:6 | (int)... | 171:c3-c6 172:c3-c6 |
|
||||
| test.cpp:171:3:171:6 | e1x1 | 171:c3-c6 172:c3-c6 |
|
||||
| test.cpp:179:10:179:22 | (...) | 179:c10-c22 179:c10-c22 |
|
||||
| test.cpp:179:17:179:17 | y | 179:c17-c17 179:c17-c17 |
|
||||
| test.cpp:179:17:179:21 | ... + ... | 179:c17-c21 179:c17-c21 |
|
||||
| test.cpp:185:17:185:17 | y | 185:c17-c17 185:c17-c17 |
|
||||
| test.cpp:202:3:202:18 | sizeof(padded_t) | 202:c3-c18 204:c3-c18 |
|
||||
| test.cpp:205:24:205:34 | sizeof(int) | 205:c24-c34 245:c25-c35 246:c25-c35 |
|
||||
| test.cpp:206:3:206:21 | alignof(int_holder) | 206:c25-c43 206:c3-c21 |
|
||||
| test.cpp:209:3:209:18 | sizeof(<expr>) | 209:c22-c37 209:c3-c18 |
|
||||
| test.cpp:209:10:209:15 | holder | 209:c10-c15 209:c29-c34 |
|
||||
| test.cpp:209:10:209:18 | (...) | 209:c10-c18 209:c29-c37 |
|
||||
| test.cpp:209:17:209:17 | x | 209:c17-c17 209:c36-c36 |
|
||||
| test.cpp:210:10:210:10 | x | 208:c27-c27 210:c10-c10 211:c11-c11 211:c24-c24 |
|
||||
| test.cpp:210:10:210:11 | (...) | 210:c10-c11 211:c11-c12 211:c24-c25 |
|
||||
| test.cpp:211:3:211:12 | alignof(<expr>) | 211:c16-c25 211:c3-c12 |
|
||||
| test.cpp:239:3:239:12 | new | 239:c3-c12 240:c3-c12 |
|
||||
| test.cpp:245:16:245:36 | new[] | 245:c16-c36 246:c16-c36 |
|
||||
| test.cpp:248:3:248:28 | delete | 248:c3-c28 249:c3-c28 |
|
||||
| test.cpp:248:10:248:28 | call to operator new | 248:c10-c28 249:c10-c28 |
|
||||
| test.cpp:248:10:248:28 | new | 248:c10-c28 249:c10-c28 |
|
||||
| test.cpp:252:10:252:32 | call to operator new | 252:c10-c32 253:c12-c34 |
|
||||
| test.cpp:252:10:252:32 | new | 252:c10-c32 253:c12-c34 |
|
||||
| test.cpp:254:3:254:25 | <error expr> | 248:c10-c28 249:c10-c28 250:c10-c28 252:c10-c32 253:c12-c34 254:c3-c25 255:c3-c25 257:c3-c19 258:c3-c19 260:c3-c23 261:c3-c23 |
|
||||
| test.cpp:254:7:254:8 | 32 | 252:c14-c15 253:c16-c17 254:c7-c8 257:c7-c8 258:c7-c8 260:c7-c8 261:c7-c8 263:c16-c17 264:c16-c17 265:c16-c17 266:c7-c8 267:c7-c8 269:c7-c8 270:c7-c8 271:c7-c8 |
|
||||
| test.cpp:254:7:254:8 | (size_t)... | 252:c14-c15 253:c16-c17 254:c7-c8 257:c7-c8 258:c7-c8 260:c7-c8 261:c7-c8 263:c16-c17 264:c16-c17 265:c16-c17 266:c7-c8 267:c7-c8 269:c7-c8 270:c7-c8 271:c7-c8 |
|
||||
| test.cpp:254:11:254:14 | (void *)... | 250:c14-c17 254:c11-c14 |
|
||||
| test.cpp:254:11:254:14 | ptr2 | 250:c14-c17 254:c11-c14 |
|
||||
| test.cpp:255:11:255:14 | (void *)... | 248:c14-c17 249:c14-c17 252:c18-c21 253:c20-c23 255:c11-c14 |
|
||||
| test.cpp:255:11:255:14 | ptr1 | 248:c14-c17 249:c14-c17 252:c18-c21 253:c20-c23 255:c11-c14 |
|
||||
| test.cpp:257:3:257:19 | call to operator new | 257:c3-c19 258:c3-c19 |
|
||||
| test.cpp:257:3:257:19 | new | 257:c3-c19 258:c3-c19 |
|
||||
| test.cpp:260:3:260:23 | call to operator new[] | 260:c3-c23 261:c3-c23 |
|
||||
| test.cpp:260:3:260:23 | new[] | 260:c3-c23 261:c3-c23 |
|
||||
| test.cpp:263:3:263:32 | delete[] | 263:c3-c32 264:c3-c32 |
|
||||
| test.cpp:263:12:263:32 | new[] | 263:c12-c32 264:c12-c32 |
|
||||
| test.cpp:263:12:263:32 | {...} | 263:c12-c32 264:c12-c32 |
|
||||
| test.cpp:266:3:266:23 | <error expr> | 263:c12-c32 264:c12-c32 265:c12-c32 266:c3-c23 267:c3-c23 269:c3-c19 270:c3-c19 271:c3-c19 |
|
||||
| test.cpp:266:3:266:23 | call to operator new[] | 263:c12-c32 264:c12-c32 265:c12-c32 266:c3-c23 267:c3-c23 269:c3-c19 270:c3-c19 271:c3-c19 |
|
||||
| test.cpp:269:3:269:19 | new[] | 269:c3-c19 270:c3-c19 |
|
||||
| test.cpp:269:3:269:19 | {...} | 269:c3-c19 270:c3-c19 |
|
||||
| test.cpp:271:15:271:15 | 3 | 265:c28-c28 271:c15-c15 35:c16-c16 |
|
||||
| test.cpp:273:3:273:12 | new[] | 273:c3-c12 274:c3-c12 |
|
||||
| test.cpp:273:11:273:11 | x | 273:c11-c11 274:c11-c11 |
|
||||
| test.cpp:285:5:285:5 | 1 | 103:c10-c11 104:c7-c7 107:c7-c7 108:c7-c7 10:c16-c16 179:c21-c21 239:c11-c11 240:c11-c11 263:c28-c28 264:c28-c28 266:c19-c19 266:c22-c22 285:c5-c5 289:c5-c5 294:c5-c5 299:c9-c9 300:c9-c9 310:c5-c5 311:c5-c5 313:c5-c5 |
|
||||
| test.cpp:286:5:286:5 | 2 | 105:c7-c7 106:c7-c7 107:c11-c11 108:c11-c11 21:c16-c16 241:c11-c11 263:c24-c24 263:c31-c31 264:c24-c24 264:c31-c31 265:c24-c24 266:c15-c15 267:c15-c15 267:c19-c19 267:c22-c22 269:c15-c15 270:c15-c15 286:c5-c5 290:c5-c5 293:c5-c5 301:c9-c9 302:c9-c9 |
|
||||
| test.cpp:299:3:299:9 | throw ... | 299:c3-c9 300:c3-c9 |
|
||||
| test.cpp:301:3:301:9 | throw ... | 301:c3-c9 302:c3-c9 |
|
||||
| test.cpp:303:3:303:7 | re-throw exception | 303:c3-c7 304:c3-c7 |
|
||||
| test.cpp:308:3:308:3 | x | 308:c3-c3 309:c3-c3 310:c3-c3 311:c3-c3 |
|
||||
| test.cpp:308:3:308:6 | access to array | 308:c3-c6 309:c3-c6 |
|
||||
| test.cpp:308:5:308:5 | 0 | 308:c5-c5 309:c5-c5 312:c5-c5 44:c9-c9 51:c25-c25 88:c12-c12 |
|
||||
| test.cpp:310:3:310:6 | access to array | 310:c3-c6 311:c3-c6 |
|
||||
| test.cpp:312:3:312:3 | y | 312:c3-c3 313:c3-c3 |
|
||||
| test.cpp:320:3:320:11 | test_18_p | 320:c3-c11 321:c3-c11 |
|
||||
| test.cpp:320:3:320:13 | call to expression | 320:c3-c13 321:c3-c13 |
|
||||
| test.cpp:324:3:324:11 | test_19_p | 324:c3-c11 325:c3-c11 326:c3-c11 |
|
||||
| test.cpp:324:3:324:17 | call to expression | 324:c3-c17 325:c3-c17 |
|
||||
| test.cpp:324:13:324:13 | x | 324:c13-c13 325:c13-c13 326:c16-c16 |
|
||||
| test.cpp:326:13:326:13 | y | 324:c16-c16 325:c16-c16 326:c13-c13 |
|
||||
| test.cpp:330:3:330:3 | x | 330:c12-c12 330:c3-c3 331:c12-c12 331:c3-c3 332:c12-c12 332:c8-c8 333:c16-c16 333:c3-c3 |
|
||||
| test.cpp:330:3:330:8 | ... == ... | 330:c3-c8 331:c3-c8 333:c3-c8 |
|
||||
| test.cpp:330:3:330:16 | ... ? ... : ... | 330:c3-c16 331:c3-c16 |
|
||||
| test.cpp:332:3:332:3 | y | 330:c16-c16 330:c8-c8 331:c16-c16 331:c8-c8 332:c16-c16 332:c3-c3 333:c12-c12 333:c8-c8 |
|
||||
@@ -0,0 +1,12 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.HashCons
|
||||
|
||||
from HashCons h
|
||||
where strictcount(h.getAnExpr()) > 1
|
||||
select
|
||||
h,
|
||||
strictconcat(Location loc
|
||||
| loc = h.getAnExpr().getLocation()
|
||||
| loc.getStartLine() +
|
||||
":c" + loc.getStartColumn() + "-c" + loc.getEndColumn()
|
||||
, " ")
|
||||
@@ -0,0 +1,8 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.HashCons
|
||||
|
||||
// Every expression should have exactly one HC.
|
||||
// So this query should have zero results.
|
||||
from Expr e
|
||||
where count(hashCons(e)) != 1
|
||||
select e, concat(HashCons h | h = hashCons(e) | h.getKind(), ", ")
|
||||
334
cpp/ql/test/library-tests/valuenumbering/HashCons/test.cpp
Normal file
334
cpp/ql/test/library-tests/valuenumbering/HashCons/test.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
int test00(int p0, int p1) {
|
||||
int x, y;
|
||||
unsigned char b;
|
||||
|
||||
x = p0 + p1;
|
||||
x = p0 + p1; // Same value as previous line. Should the assignment also be matched?
|
||||
y = x;
|
||||
}
|
||||
|
||||
int global01 = 1;
|
||||
|
||||
int test01(int p0, int p1) {
|
||||
int x, y;
|
||||
unsigned char b;
|
||||
|
||||
x = p0 + p1 + global01;
|
||||
x = p0 + p1 + global01; // Same structure as previous line.
|
||||
y = x; // x is the same as x above
|
||||
}
|
||||
|
||||
int global02 = 2;
|
||||
|
||||
void change_global02(); // Just a declaration
|
||||
|
||||
int test02(int p0, int p1) {
|
||||
int x, y;
|
||||
unsigned char b;
|
||||
|
||||
x = p0 + p1 + global02;
|
||||
change_global02();
|
||||
x = p0 + p1 + global02; // same HashCons as above
|
||||
y = x;
|
||||
}
|
||||
|
||||
int global03 = 3;
|
||||
|
||||
void change_global03(); // Just a declaration
|
||||
|
||||
int test03(int p0, int p1, int* p2) {
|
||||
int x, y;
|
||||
unsigned char b;
|
||||
|
||||
x = p0 + p1 + global03;
|
||||
*p2 = 0;
|
||||
x = p0 + p1 + global03; // same HashCons as 43
|
||||
y = x;
|
||||
}
|
||||
|
||||
unsigned int my_strspn(const char *str, const char *chars) {
|
||||
const char *ptr;
|
||||
unsigned int result = 0;
|
||||
|
||||
while (*str != '\0') {
|
||||
// check *str against chars
|
||||
ptr = chars;
|
||||
while ((*ptr != *str) && (*ptr != '\0')) {ptr++;}
|
||||
|
||||
// update
|
||||
if (*ptr == '\0') { // ptr same as ptr on lines 53 and 56
|
||||
break;
|
||||
}
|
||||
result++;
|
||||
}
|
||||
|
||||
return result; // result same as result on line 62
|
||||
}
|
||||
|
||||
int getAValue();
|
||||
|
||||
struct two_values {
|
||||
signed short val1;
|
||||
signed short val2;
|
||||
};
|
||||
|
||||
void test04(two_values *vals)
|
||||
{
|
||||
signed short v = getAValue(); // should this match getAValue() on line 80?
|
||||
|
||||
if (v < vals->val1 + vals->val2) {
|
||||
v = getAValue(); // should this match getAValue() on line 77?
|
||||
}
|
||||
}
|
||||
|
||||
void test05(int x, int y, void *p)
|
||||
{
|
||||
int v;
|
||||
|
||||
v = p != 0 ? x : y;
|
||||
}
|
||||
|
||||
int regression_test00() {
|
||||
int x = x = 10;
|
||||
return x;
|
||||
}
|
||||
|
||||
void test06(int x) {
|
||||
x++;
|
||||
x++; // x++ is matched
|
||||
}
|
||||
|
||||
// literals
|
||||
void test07() {
|
||||
int x = 1;
|
||||
x = 1;
|
||||
x = 2;
|
||||
x = 2;
|
||||
x = 1 + 2;
|
||||
x = 1 + 2;
|
||||
|
||||
char *str = "1";
|
||||
str = "1";
|
||||
str = "2";
|
||||
str = "2";
|
||||
|
||||
float y = 0.0;
|
||||
y = 0.0;
|
||||
y = 0.5;
|
||||
y = 0.5;
|
||||
}
|
||||
|
||||
void test08() {
|
||||
test07();
|
||||
test07();
|
||||
|
||||
my_strspn("foo", "bar");
|
||||
my_strspn("foo", "bar");
|
||||
|
||||
|
||||
my_strspn("bar", "foo");
|
||||
}
|
||||
|
||||
class IntHolder {
|
||||
int myInt;
|
||||
|
||||
int getInt() {
|
||||
return myInt;
|
||||
}
|
||||
|
||||
public:
|
||||
int getDoubledInt() {
|
||||
return getInt() + this->getInt(); // getInt() and this->getInt() should be the same
|
||||
}
|
||||
};
|
||||
|
||||
int test09(IntHolder ih) {
|
||||
return ih.getDoubledInt() + ih.getDoubledInt();
|
||||
}
|
||||
|
||||
int test10(int x) {
|
||||
x++ + x++;
|
||||
x++ + x++; // same as above
|
||||
return ++x; // ++x is not the same as x++
|
||||
}
|
||||
|
||||
void* test11() {
|
||||
nullptr == nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
enum t1 {
|
||||
e1x1 = 1,
|
||||
e1x2 = 2
|
||||
};
|
||||
|
||||
enum t2 {
|
||||
e2x1 = 1,
|
||||
e2x2 = 2
|
||||
};
|
||||
|
||||
int test12() {
|
||||
e1x1 == e2x1;
|
||||
e1x1 == e2x2;
|
||||
return e1x2;
|
||||
}
|
||||
|
||||
#define SQUARE(x) ((x) * (x))
|
||||
|
||||
int test13(int y) {
|
||||
return SQUARE(y + 1);
|
||||
}
|
||||
|
||||
#define SQUARE(x) x * x
|
||||
|
||||
int test14(int y) {
|
||||
return SQUARE(y);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
char y;
|
||||
} padded_t;
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
} int_holder;
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
void *malloc(size_t size);
|
||||
|
||||
int test15(int x) {
|
||||
sizeof(padded_t);
|
||||
alignof(padded_t);
|
||||
sizeof(padded_t);
|
||||
sizeof(int_holder) + sizeof(int);
|
||||
alignof(int_holder) + alignof(int_holder);
|
||||
|
||||
int_holder holder = {x: x};
|
||||
sizeof(holder.x) + sizeof(holder.x);
|
||||
sizeof(x);
|
||||
alignof(x) + alignof(x);
|
||||
}
|
||||
|
||||
static void *operator new(size_t size, void *placement) {
|
||||
return placement;
|
||||
}
|
||||
|
||||
static void *operator new(size_t size, size_t alignment, void *placement) {
|
||||
return placement;
|
||||
}
|
||||
|
||||
static void *operator new(size_t size, size_t alignment) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void *operator new[](size_t size, void *placement) {
|
||||
return placement;
|
||||
}
|
||||
|
||||
static void *operator new[](size_t size, size_t alignment, void *placement) {
|
||||
return placement;
|
||||
}
|
||||
|
||||
static void *operator new[](size_t size, size_t alignment) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void test16(int y, int z) {
|
||||
new int(1);
|
||||
new int(1);
|
||||
new int(2);
|
||||
|
||||
int x;
|
||||
|
||||
char *ptr1 = new char[sizeof(int)];
|
||||
char *ptr2 = new char[sizeof(int)];
|
||||
|
||||
delete new(ptr1) IntHolder;
|
||||
delete new(ptr1) IntHolder;
|
||||
delete new(ptr2) IntHolder;
|
||||
|
||||
delete new(32, ptr1) IntHolder;
|
||||
delete[] new(32, ptr1) IntHolder;
|
||||
new(32, ptr2) IntHolder;
|
||||
new(16, ptr1) IntHolder;
|
||||
|
||||
new(32) IntHolder;
|
||||
new(32) IntHolder;
|
||||
|
||||
new(32) IntHolder[10];
|
||||
new(32) IntHolder[10];
|
||||
|
||||
delete[] new(32) int[2] {1, 2};
|
||||
delete[] new(32) int[2] {1, 2};
|
||||
delete[] new(32) int[2] {3, 4};
|
||||
new(32) int[2] {1, 1};
|
||||
new(32) int[2] {2, 2};
|
||||
|
||||
new(32) int[2] {};
|
||||
new(32) int[2] {};
|
||||
new(32) int[3] {};
|
||||
|
||||
new int[x];
|
||||
new int[x];
|
||||
new int[z];
|
||||
}
|
||||
|
||||
typedef struct point{
|
||||
int x;
|
||||
int y;
|
||||
} point_t;
|
||||
|
||||
void test17() {
|
||||
point_t p1 = {
|
||||
1,
|
||||
2
|
||||
};
|
||||
point_t p2 = {
|
||||
1,
|
||||
2
|
||||
};
|
||||
point_t p3 = {
|
||||
2,
|
||||
1
|
||||
};
|
||||
}
|
||||
|
||||
void test18() {
|
||||
throw 1;
|
||||
throw 1;
|
||||
throw 2;
|
||||
throw 2;
|
||||
throw;
|
||||
throw;
|
||||
}
|
||||
|
||||
void test19(int *x, int *y) {
|
||||
x[0];
|
||||
x[0];
|
||||
x[1];
|
||||
x[1];
|
||||
y[0];
|
||||
y[1];
|
||||
}
|
||||
|
||||
void test20(int *x, int *y) {
|
||||
void (*test_18_p)() = &test18;
|
||||
void (*test_17_p)() = &test17;
|
||||
void (*test_19_p)(int *, int *) = &test19;
|
||||
test_18_p();
|
||||
test_18_p();
|
||||
test_17_p();
|
||||
|
||||
test_19_p(x, y);
|
||||
test_19_p(x, y);
|
||||
test_19_p(y, x);
|
||||
}
|
||||
|
||||
void test21(int x, int y) {
|
||||
x == y ? x : y;
|
||||
x == y ? x : y;
|
||||
y == x ? x : y;
|
||||
x == y ? y : x;
|
||||
}
|
||||
Reference in New Issue
Block a user