mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
C++: Operands as IPA types
@rdmarsh2 has been working on various queries and libraries on top of the IR, and has pointed out that having to always refer to an operand of an instruction by the pair of (instruction, operandTag) makes using the IR a bit clunky. This PR adds a new `Operand` IPA type that represents an operand of an instruction. `OperandTag` still exists, but is now an internal type used only in the IR implementation.
This commit is contained in:
@@ -19,10 +19,10 @@
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/FunctionIR.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/FunctionIR.qll"
|
||||
],
|
||||
"C++ IR OperandTag": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/OperandTag.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/OperandTag.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/OperandTag.qll"
|
||||
"C++ IR Operand": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll"
|
||||
],
|
||||
"C++ IR IRImpl": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll",
|
||||
|
||||
@@ -16,7 +16,7 @@ class MemoryAccessKind extends TMemoryAccessKind {
|
||||
|
||||
/**
|
||||
* The operand or result accesses memory at the address specified by the
|
||||
* `LoadStoreAddressOperand` on the same instruction.
|
||||
* `AddressOperand` on the same instruction.
|
||||
*/
|
||||
class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
|
||||
override string toString() {
|
||||
|
||||
@@ -2,7 +2,7 @@ import FunctionIR
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import IRVariable
|
||||
import OperandTag
|
||||
import Operand
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@ private import internal.IRInternal
|
||||
import FunctionIR
|
||||
import IRBlock
|
||||
import IRVariable
|
||||
import OperandTag
|
||||
import Operand
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
|
||||
class InstructionTag = Construction::InstructionTagType;
|
||||
|
||||
@@ -22,21 +23,21 @@ module InstructionSanity {
|
||||
exists(Opcode opcode |
|
||||
opcode = instr.getOpcode() and
|
||||
(
|
||||
opcode instanceof UnaryOpcode and tag instanceof UnaryOperand or
|
||||
opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or
|
||||
(
|
||||
opcode instanceof BinaryOpcode and
|
||||
(
|
||||
tag instanceof LeftOperand or
|
||||
tag instanceof RightOperand
|
||||
tag instanceof LeftOperandTag or
|
||||
tag instanceof RightOperandTag
|
||||
)
|
||||
) or
|
||||
opcode instanceof CopyOpcode and tag instanceof CopySourceOperand or
|
||||
opcode instanceof MemoryAccessOpcode and tag instanceof LoadStoreAddressOperand or
|
||||
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperand or
|
||||
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperand or
|
||||
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperand or
|
||||
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperand or
|
||||
opcode instanceof Opcode::Call and tag instanceof CallTargetOperand
|
||||
opcode instanceof CopyOpcode and tag instanceof CopySourceOperandTag or
|
||||
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or
|
||||
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or
|
||||
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperandTag or
|
||||
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperandTag or
|
||||
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or
|
||||
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -45,26 +46,34 @@ module InstructionSanity {
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, OperandTag tag) {
|
||||
expectsOperand(instr, tag) and not exists(instr.getOperand(tag))
|
||||
expectsOperand(instr, tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag) and
|
||||
not expectsOperand(instr, tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperand) and
|
||||
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperand) and
|
||||
not (instr instanceof PhiInstruction and tag instanceof PhiOperand)
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
|
||||
strictcount(instr.getOperand(tag)) > 1 and
|
||||
not tag instanceof UnmodeledUseOperand
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +83,7 @@ module InstructionSanity {
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiOperand operand |
|
||||
exists(instr.getOperand(operand)) and
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
@@ -98,14 +107,13 @@ module InstructionSanity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `op` consumes an operand `operand` that was defined in
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(
|
||||
Instruction op, Instruction operand, OperandTag tag
|
||||
) {
|
||||
operand = op.getOperand(tag) and
|
||||
operand.getFunctionIR() != op.getFunctionIR()
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getInstruction() = instr and
|
||||
operand.getDefinitionInstruction() = defInstr and
|
||||
instr.getFunctionIR() != defInstr.getFunctionIR()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,20 +254,6 @@ class Instruction extends Construction::TInstruction {
|
||||
result = getResultId() + "(" + getResultTypeString() + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the specified operand, suitable for display in IR
|
||||
* dumps. This consists of the result ID of the instruction consumed by the
|
||||
* operand, plus a label identifying the operand kind.
|
||||
*
|
||||
* For example: `this:r3_5`
|
||||
*/
|
||||
string getOperandString(OperandTag tag) {
|
||||
exists(Instruction operand |
|
||||
operand = getOperand(tag) and
|
||||
result = tag.getLabel() + operand.getResultId()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operands of this instruction, suitable for
|
||||
* display in IR dumps.
|
||||
@@ -267,9 +261,9 @@ class Instruction extends Construction::TInstruction {
|
||||
* Example: `func:r3_4, this:r3_5`
|
||||
*/
|
||||
string getOperandsString() {
|
||||
result = concat(OperandTag tag, Instruction operand |
|
||||
operand = getOperand(tag) |
|
||||
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
|
||||
result = concat(Operand operand |
|
||||
operand = getAnOperand() |
|
||||
operand.getDumpString(), ", " order by operand.getDumpSortOrder()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -333,7 +327,6 @@ class Instruction extends Construction::TInstruction {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(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`.
|
||||
@@ -397,35 +390,19 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction that produced the value of the specified source
|
||||
* operand.
|
||||
* Gets all direct uses of the result of this instruction.
|
||||
*/
|
||||
final Instruction getOperand(OperandTag tag) {
|
||||
result = Construction::getInstructionOperand(this, tag)
|
||||
final Operand getAUse() {
|
||||
result.getDefinitionInstruction() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all instructions consumed by this instruction's operands.
|
||||
* Gets all of this instruction's operands.
|
||||
*/
|
||||
final Instruction getAnOperand() {
|
||||
result = getOperand(_)
|
||||
final Operand getAnOperand() {
|
||||
result.getInstruction() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this instruction has a memory operand with the specified tag.
|
||||
*/
|
||||
final predicate isMemoryOperand(OperandTag tag) {
|
||||
exists(getOperandMemoryAccess(tag))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of memory access performed by the specified operand. Holds
|
||||
* only for memory operands.
|
||||
*/
|
||||
MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this instruction produces a memory result.
|
||||
*/
|
||||
@@ -461,9 +438,7 @@ class Instruction extends Construction::TInstruction {
|
||||
// Register results are always in SSA form.
|
||||
not hasMemoryResult() or
|
||||
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
|
||||
not exists(Instruction useInstr, UnmodeledUseOperand useTag |
|
||||
this = useInstr.getOperand(useTag)
|
||||
)
|
||||
not (getAUse() instanceof UnmodeledUseOperand)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -602,7 +577,7 @@ class FieldAddressInstruction extends FieldInstruction {
|
||||
}
|
||||
|
||||
final Instruction getObjectAddress() {
|
||||
result = getOperand(unaryOperand())
|
||||
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,12 +615,7 @@ class ReturnValueInstruction extends ReturnInstruction {
|
||||
}
|
||||
|
||||
final Instruction getReturnValue() {
|
||||
result = getOperand(returnValueOperand())
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(ReturnValueOperand))) and
|
||||
result instanceof IndirectMemoryAccess
|
||||
result = getAnOperand().(ReturnValueOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +625,7 @@ class CopyInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getSourceValue() {
|
||||
result = getOperand(copySourceOperand())
|
||||
result = getAnOperand().(CopySourceOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,13 +640,8 @@ class LoadInstruction extends CopyInstruction {
|
||||
opcode instanceof Opcode::Load
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(CopySourceOperand))) and
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
|
||||
final Instruction getSourceAddress() {
|
||||
result = getOperand(loadStoreAddressOperand())
|
||||
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,7 +655,7 @@ class StoreInstruction extends CopyInstruction {
|
||||
}
|
||||
|
||||
final Instruction getDestinationAddress() {
|
||||
result = getOperand(loadStoreAddressOperand())
|
||||
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,7 +665,7 @@ class ConditionalBranchInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getCondition() {
|
||||
result = getOperand(conditionOperand())
|
||||
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
final Instruction getTrueSuccessor() {
|
||||
@@ -758,11 +723,11 @@ class BinaryInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getLeftOperand() {
|
||||
result = getOperand(leftOperand())
|
||||
result = getAnOperand().(LeftOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
final Instruction getRightOperand() {
|
||||
result = getOperand(rightOperand())
|
||||
result = getAnOperand().(RightOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,7 +838,7 @@ class UnaryInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getOperand() {
|
||||
result = getOperand(unaryOperand())
|
||||
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -992,6 +957,7 @@ class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||
* of this relational instruction, that is, the side that is larger
|
||||
@@ -1011,6 +977,7 @@ class RelationalInstruction extends CompareInstruction {
|
||||
Instruction getLesserOperand() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
|
||||
*/
|
||||
@@ -1097,7 +1064,7 @@ class SwitchInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getExpression() {
|
||||
result = getOperand(conditionOperand())
|
||||
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
final Instruction getACaseSuccessor() {
|
||||
@@ -1117,7 +1084,7 @@ class CallInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getCallTarget() {
|
||||
result = getOperand(callTargetOperand())
|
||||
result = getAnOperand().(CallTargetOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1138,24 +1105,18 @@ class ThrowValueInstruction extends ThrowInstruction {
|
||||
opcode instanceof Opcode::ThrowValue
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(ExceptionOperand))) and
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the address of the exception thrown by this instruction.
|
||||
*/
|
||||
final Instruction getExceptionAddress() {
|
||||
result = getOperand(loadStoreAddressOperand())
|
||||
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exception thrown by this instruction.
|
||||
*/
|
||||
final Instruction getException() {
|
||||
result = getOperand(exceptionOperand())
|
||||
result = getAnOperand().(ExceptionOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,11 +1197,6 @@ class UnmodeledUseInstruction extends Instruction {
|
||||
override string getOperandsString() {
|
||||
result = "mu*"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(UnmodeledUseOperand))) and
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
class PhiInstruction extends Instruction {
|
||||
@@ -1248,11 +1204,6 @@ class PhiInstruction extends Instruction {
|
||||
opcode instanceof Opcode::Phi
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(PhiOperand))) and
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
|
||||
private newtype TOperand =
|
||||
TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getInstructionOperand(instr, tag)
|
||||
} or
|
||||
TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) {
|
||||
defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock)
|
||||
}
|
||||
|
||||
/**
|
||||
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
string toString() {
|
||||
result = "Operand"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
Instruction getInstruction() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand.
|
||||
*/
|
||||
Instruction getDefinitionInstruction() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a prefix to use when dumping the operand in an operand list.
|
||||
*/
|
||||
string getDumpLabel() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing this operand, suitable for display in IR dumps. This consists of the
|
||||
* result ID of the instruction consumed by the operand, plus a label identifying the operand
|
||||
* kind.
|
||||
*
|
||||
* For example: `this:r3_5`
|
||||
*/
|
||||
final string getDumpString() {
|
||||
result = getDumpLabel() + getDefinitionInstruction().getResultId()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order in which the operand should be sorted in the operand list.
|
||||
*/
|
||||
int getDumpSortOrder() {
|
||||
result = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of memory access performed by the operand. Holds only for memory operands.
|
||||
*/
|
||||
MemoryAccessKind getMemoryAccess() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the operand that holds the memory address from which the current operand loads its
|
||||
* value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2`
|
||||
* is `r1`.
|
||||
*/
|
||||
final AddressOperand getAddressOperand() {
|
||||
getMemoryAccess() instanceof IndirectMemoryAccess and
|
||||
result.getInstruction() = getInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand that is not an operand of a `PhiInstruction`.
|
||||
*/
|
||||
class NonPhiOperand extends Operand, TNonPhiOperand {
|
||||
Instruction instr;
|
||||
Instruction defInstr;
|
||||
OperandTag tag;
|
||||
|
||||
NonPhiOperand() {
|
||||
this = TNonPhiOperand(instr, tag, defInstr)
|
||||
}
|
||||
|
||||
override final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
|
||||
override final Instruction getDefinitionInstruction() {
|
||||
result = defInstr
|
||||
}
|
||||
|
||||
override final string getDumpLabel() {
|
||||
result = tag.getLabel()
|
||||
}
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = tag.getSortOrder()
|
||||
}
|
||||
|
||||
final OperandTag getOperandTag() {
|
||||
result = tag
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class AddressOperand extends NonPhiOperand {
|
||||
AddressOperand() {
|
||||
this = TNonPhiOperand(_, addressOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Address"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends NonPhiOperand {
|
||||
CopySourceOperand() {
|
||||
this = TNonPhiOperand(_, copySourceOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
instr.getOpcode() instanceof Opcode::Load and
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends NonPhiOperand {
|
||||
UnaryOperand() {
|
||||
this = TNonPhiOperand(_, unaryOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends NonPhiOperand {
|
||||
LeftOperand() {
|
||||
this = TNonPhiOperand(_, leftOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends NonPhiOperand {
|
||||
RightOperand() {
|
||||
this = TNonPhiOperand(_, rightOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends NonPhiOperand {
|
||||
ReturnValueOperand() {
|
||||
this = TNonPhiOperand(_, returnValueOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends NonPhiOperand {
|
||||
ExceptionOperand() {
|
||||
this = TNonPhiOperand(_, exceptionOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends NonPhiOperand {
|
||||
ConditionOperand() {
|
||||
this = TNonPhiOperand(_, conditionOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends NonPhiOperand {
|
||||
UnmodeledUseOperand() {
|
||||
this = TNonPhiOperand(_, unmodeledUseOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Call` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends NonPhiOperand {
|
||||
CallTargetOperand() {
|
||||
this = TNonPhiOperand(_, callTargetOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
class ArgumentOperand extends NonPhiOperand {
|
||||
ArgumentOperand() {
|
||||
exists(ArgumentOperandTag argTag |
|
||||
this = TNonPhiOperand(_, argTag, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TNonPhiOperand(_, thisArgumentOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "ThisArgument"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
exists(PositionalArgumentOperandTag argTag |
|
||||
this = TNonPhiOperand(_, argTag, _) and
|
||||
argIndex = argTag.getArgIndex()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
class PhiOperand extends Operand, TPhiOperand {
|
||||
PhiInstruction instr;
|
||||
Instruction defInstr;
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(instr, defInstr, predecessorBlock)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final PhiInstruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
|
||||
override final Instruction getDefinitionInstruction() {
|
||||
result = defInstr
|
||||
}
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getDumpLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the predecessor block from which this value comes.
|
||||
*/
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand that reads a value from memory.
|
||||
*/
|
||||
class MemoryOperand extends Operand {
|
||||
MemoryOperand() {
|
||||
exists(getMemoryAccess())
|
||||
}
|
||||
}
|
||||
@@ -46,18 +46,20 @@ private IntValue getFieldBitOffset(Field field) {
|
||||
* not result in any address held in that operand from escaping beyond the
|
||||
* instruction.
|
||||
*/
|
||||
predicate operandIsConsumedWithoutEscaping(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// The source/destination address of a Load/Store does not escape (but the
|
||||
// loaded/stored value could).
|
||||
tag instanceof LoadStoreAddressOperand or
|
||||
// Neither operand of a Compare escapes.
|
||||
instr instanceof CompareInstruction or
|
||||
// Neither operand of a PointerDiff escapes.
|
||||
instr instanceof PointerDiffInstruction or
|
||||
// Converting an address to a `bool` does not escape the address.
|
||||
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
||||
predicate operandIsConsumedWithoutEscaping(Operand operand) {
|
||||
// The source/destination address of a Load/Store does not escape (but the
|
||||
// loaded/stored value could).
|
||||
operand instanceof AddressOperand or
|
||||
exists (Instruction instr |
|
||||
instr = operand.getInstruction() and
|
||||
(
|
||||
// Neither operand of a Compare escapes.
|
||||
instr instanceof CompareInstruction or
|
||||
// Neither operand of a PointerDiff escapes.
|
||||
instr instanceof PointerDiffInstruction or
|
||||
// Converting an address to a `bool` does not escape the address.
|
||||
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,43 +98,44 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
|
||||
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
||||
* a constant, then `bitOffset` is unknown.
|
||||
*/
|
||||
predicate operandIsPropagated(Instruction instr, OperandTag tag,
|
||||
IntValue bitOffset) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
) or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
) or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
||||
exists(Instruction instr |
|
||||
instr = operand.getInstruction() and
|
||||
(
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
) or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, Type resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultType() and
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
) or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
) or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
(
|
||||
resultType instanceof PointerType or
|
||||
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
|
||||
) and
|
||||
bitOffset = 0
|
||||
) or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
||||
// A copy propagates the source value.
|
||||
tag instanceof CopySourceOperand and bitOffset = 0
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
) or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, Type resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultType() and
|
||||
(
|
||||
resultType instanceof PointerType or
|
||||
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
|
||||
) and
|
||||
bitOffset = 0
|
||||
) or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
||||
// A copy propagates the source value.
|
||||
operand instanceof CopySourceOperand and bitOffset = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -140,16 +143,15 @@ predicate operandIsPropagated(Instruction instr, OperandTag tag,
|
||||
* Holds if any address held in operand number `tag` of instruction `instr`
|
||||
* escapes outside the domain of the analysis.
|
||||
*/
|
||||
predicate operandEscapes(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
predicate operandEscapes(Operand operand) {
|
||||
// Conservatively assume that the address escapes unless one of the following
|
||||
// holds:
|
||||
not (
|
||||
// The operand is used in a way that does not escape the instruction
|
||||
operandIsConsumedWithoutEscaping(instr, tag) or
|
||||
operandIsConsumedWithoutEscaping(operand) or
|
||||
// The address is propagated to the result of the instruction, but that
|
||||
// result does not itself escape.
|
||||
operandIsPropagated(instr, tag, _) and not resultEscapes(instr)
|
||||
operandIsPropagated(operand, _) and not resultEscapes(operand.getInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -159,10 +161,7 @@ predicate operandEscapes(Instruction instr, OperandTag tag) {
|
||||
*/
|
||||
predicate resultEscapes(Instruction instr) {
|
||||
// The result escapes if it has at least one use that escapes.
|
||||
exists(Instruction useInstr, OperandTag useOperandTag |
|
||||
useInstr.getOperand(useOperandTag) = instr and
|
||||
operandEscapes(useInstr, useOperandTag)
|
||||
)
|
||||
operandEscapes(instr.getAUse())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,12 +202,12 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
|
||||
instr.(VariableAddressInstruction).getVariable() = var and
|
||||
bitOffset = 0
|
||||
) or
|
||||
exists(OperandTag operandTag, IntValue originalBitOffset,
|
||||
IntValue propagatedBitOffset |
|
||||
exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset |
|
||||
operand = instr.getAnOperand() and
|
||||
// If an operand is propagated, then the result points to the same variable,
|
||||
// offset by the bit offset from the propagation.
|
||||
resultPointsTo(instr.getOperand(operandTag), var, originalBitOffset) and
|
||||
operandIsPropagated(instr, operandTag, propagatedBitOffset) and
|
||||
resultPointsTo(operand.getDefinitionInstruction(), var, originalBitOffset) and
|
||||
operandIsPropagated(operand, propagatedBitOffset) and
|
||||
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,30 +1,13 @@
|
||||
import SSAConstructionInternal
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
import NewIR
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import NewIR
|
||||
import IRBlockConstruction as BlockConstruction
|
||||
|
||||
import Cached
|
||||
cached private module Cached {
|
||||
|
||||
private OldIR::OperandTag getOldOperandTag(OperandTag newTag) {
|
||||
newTag instanceof LoadStoreAddressOperand and result instanceof OldIR::LoadStoreAddressOperand or
|
||||
newTag instanceof CopySourceOperand and result instanceof OldIR::CopySourceOperand or
|
||||
newTag instanceof UnaryOperand and result instanceof OldIR::UnaryOperand or
|
||||
newTag instanceof LeftOperand and result instanceof OldIR::LeftOperand or
|
||||
newTag instanceof RightOperand and result instanceof OldIR::RightOperand or
|
||||
newTag instanceof ReturnValueOperand and result instanceof OldIR::ReturnValueOperand or
|
||||
newTag instanceof ExceptionOperand and result instanceof OldIR::ExceptionOperand or
|
||||
newTag instanceof ConditionOperand and result instanceof OldIR::ConditionOperand or
|
||||
newTag instanceof UnmodeledUseOperand and result instanceof OldIR::UnmodeledUseOperand or
|
||||
newTag instanceof CallTargetOperand and result instanceof OldIR::CallTargetOperand or
|
||||
newTag instanceof ThisArgumentOperand and result instanceof OldIR::ThisArgumentOperand or
|
||||
exists(PositionalArgumentOperand newArg |
|
||||
newArg = newTag and
|
||||
result.(OldIR::PositionalArgumentOperand).getArgIndex() = newArg.getArgIndex()
|
||||
)
|
||||
}
|
||||
|
||||
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
|
||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
}
|
||||
@@ -49,14 +32,6 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(OldIR::PositionalArgumentOperand oldOperand |
|
||||
argIndex = oldOperand.getArgIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached OldIR::Instruction getOldInstruction(Instruction instr) {
|
||||
instr.getTag() = WrappedInstructionTag(result)
|
||||
}
|
||||
@@ -136,17 +111,18 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
exists(OldIR::Instruction oldUse, OldIR::OperandTag oldTag |
|
||||
oldUse = getOldInstruction(instruction) and
|
||||
oldTag = getOldOperandTag(tag) and
|
||||
if oldUse.isMemoryOperand(oldTag) then (
|
||||
exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
oldOperand = oldInstruction.getAnOperand() and
|
||||
tag = oldOperand.getOperandTag() and
|
||||
if oldOperand instanceof OldIR::MemoryOperand then (
|
||||
(
|
||||
if exists(Alias::getOperandMemoryAccess(oldUse, oldTag)) then (
|
||||
if exists(Alias::getOperandMemoryAccess(oldOperand)) then (
|
||||
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex |
|
||||
vvar = Alias::getOperandMemoryAccess(oldUse, oldTag).getVirtualVariable() and
|
||||
vvar = Alias::getOperandMemoryAccess(oldOperand).getVirtualVariable() and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldUse) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldInstruction) and
|
||||
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewInstruction(defBlock.getInstruction(defIndex))
|
||||
@@ -162,25 +138,24 @@ cached private module Cached {
|
||||
// `UnmodeledUse` instruction.
|
||||
exists(OldIR::Instruction oldDefinition |
|
||||
instruction instanceof UnmodeledUseInstruction and
|
||||
tag instanceof UnmodeledUseOperand and
|
||||
oldDefinition = oldUse.getOperand(oldTag) and
|
||||
tag instanceof UnmodeledUseOperandTag and
|
||||
oldDefinition = oldOperand.getDefinitionInstruction() and
|
||||
not exists(Alias::getResultMemoryAccess(oldDefinition)) and
|
||||
result = getNewInstruction(oldDefinition)
|
||||
)
|
||||
)
|
||||
else
|
||||
result = getNewInstruction(oldUse.getOperand(oldTag))
|
||||
) or
|
||||
result = getPhiInstructionOperand(instruction.(PhiInstruction), tag.(PhiOperand))
|
||||
result = getNewInstruction(oldOperand.getDefinitionInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionOperand(PhiInstruction instr, PhiOperand tag) {
|
||||
cached Instruction getPhiInstructionOperand(PhiInstruction instr, IRBlock newPredecessorBlock) {
|
||||
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
|
||||
hasPhiNode(vvar, phiBlock) and
|
||||
predBlock = phiBlock.getAPredecessor() and
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
tag.getPredecessorBlock() = getNewBlock(predBlock) and
|
||||
newPredecessorBlock = getNewBlock(predBlock) and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
||||
if defIndex >= 0 then
|
||||
@@ -277,7 +252,7 @@ cached private module Cached {
|
||||
private predicate hasUse(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction use, OldIR::IRBlock block, int index) {
|
||||
exists(Alias::MemoryAccess access |
|
||||
access = Alias::getOperandMemoryAccess(use, _) and
|
||||
access = Alias::getOperandMemoryAccess(use.getAnOperand()) and
|
||||
block.getInstruction(index) = use and
|
||||
vvar = access.getVirtualVariable()
|
||||
)
|
||||
|
||||
@@ -2,7 +2,8 @@ import SimpleSSAInternal
|
||||
import cpp
|
||||
import Alias
|
||||
private import InputIR
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.Overlap
|
||||
|
||||
private newtype TVirtualVariable =
|
||||
MkVirtualVariable(IRVariable var) {
|
||||
@@ -69,15 +70,15 @@ Overlap getOverlap(MemoryAccess def, MemoryAccess use) {
|
||||
MemoryAccess getResultMemoryAccess(Instruction instr) {
|
||||
exists(IRVariable var |
|
||||
instr.getResultMemoryAccess() instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
resultPointsTo(instr.getAnOperand().(AddressOperand).getDefinitionInstruction(),
|
||||
var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
|
||||
MemoryAccess getOperandMemoryAccess(Instruction instr, OperandTag tag) {
|
||||
MemoryAccess getOperandMemoryAccess(Operand operand) {
|
||||
exists(IRVariable var |
|
||||
instr.getOperandMemoryAccess(tag) instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
resultPointsTo(operand.getAddressOperand().getDefinitionInstruction(), var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import FunctionIR
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import IRVariable
|
||||
import OperandTag
|
||||
import Operand
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@ private import internal.IRInternal
|
||||
import FunctionIR
|
||||
import IRBlock
|
||||
import IRVariable
|
||||
import OperandTag
|
||||
import Operand
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
|
||||
class InstructionTag = Construction::InstructionTagType;
|
||||
|
||||
@@ -22,21 +23,21 @@ module InstructionSanity {
|
||||
exists(Opcode opcode |
|
||||
opcode = instr.getOpcode() and
|
||||
(
|
||||
opcode instanceof UnaryOpcode and tag instanceof UnaryOperand or
|
||||
opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or
|
||||
(
|
||||
opcode instanceof BinaryOpcode and
|
||||
(
|
||||
tag instanceof LeftOperand or
|
||||
tag instanceof RightOperand
|
||||
tag instanceof LeftOperandTag or
|
||||
tag instanceof RightOperandTag
|
||||
)
|
||||
) or
|
||||
opcode instanceof CopyOpcode and tag instanceof CopySourceOperand or
|
||||
opcode instanceof MemoryAccessOpcode and tag instanceof LoadStoreAddressOperand or
|
||||
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperand or
|
||||
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperand or
|
||||
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperand or
|
||||
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperand or
|
||||
opcode instanceof Opcode::Call and tag instanceof CallTargetOperand
|
||||
opcode instanceof CopyOpcode and tag instanceof CopySourceOperandTag or
|
||||
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or
|
||||
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or
|
||||
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperandTag or
|
||||
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperandTag or
|
||||
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or
|
||||
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -45,26 +46,34 @@ module InstructionSanity {
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, OperandTag tag) {
|
||||
expectsOperand(instr, tag) and not exists(instr.getOperand(tag))
|
||||
expectsOperand(instr, tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag) and
|
||||
not expectsOperand(instr, tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperand) and
|
||||
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperand) and
|
||||
not (instr instanceof PhiInstruction and tag instanceof PhiOperand)
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
|
||||
strictcount(instr.getOperand(tag)) > 1 and
|
||||
not tag instanceof UnmodeledUseOperand
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +83,7 @@ module InstructionSanity {
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiOperand operand |
|
||||
exists(instr.getOperand(operand)) and
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
@@ -98,14 +107,13 @@ module InstructionSanity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `op` consumes an operand `operand` that was defined in
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(
|
||||
Instruction op, Instruction operand, OperandTag tag
|
||||
) {
|
||||
operand = op.getOperand(tag) and
|
||||
operand.getFunctionIR() != op.getFunctionIR()
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getInstruction() = instr and
|
||||
operand.getDefinitionInstruction() = defInstr and
|
||||
instr.getFunctionIR() != defInstr.getFunctionIR()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,20 +254,6 @@ class Instruction extends Construction::TInstruction {
|
||||
result = getResultId() + "(" + getResultTypeString() + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the specified operand, suitable for display in IR
|
||||
* dumps. This consists of the result ID of the instruction consumed by the
|
||||
* operand, plus a label identifying the operand kind.
|
||||
*
|
||||
* For example: `this:r3_5`
|
||||
*/
|
||||
string getOperandString(OperandTag tag) {
|
||||
exists(Instruction operand |
|
||||
operand = getOperand(tag) and
|
||||
result = tag.getLabel() + operand.getResultId()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operands of this instruction, suitable for
|
||||
* display in IR dumps.
|
||||
@@ -267,9 +261,9 @@ class Instruction extends Construction::TInstruction {
|
||||
* Example: `func:r3_4, this:r3_5`
|
||||
*/
|
||||
string getOperandsString() {
|
||||
result = concat(OperandTag tag, Instruction operand |
|
||||
operand = getOperand(tag) |
|
||||
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
|
||||
result = concat(Operand operand |
|
||||
operand = getAnOperand() |
|
||||
operand.getDumpString(), ", " order by operand.getDumpSortOrder()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -333,7 +327,6 @@ class Instruction extends Construction::TInstruction {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(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`.
|
||||
@@ -397,35 +390,19 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction that produced the value of the specified source
|
||||
* operand.
|
||||
* Gets all direct uses of the result of this instruction.
|
||||
*/
|
||||
final Instruction getOperand(OperandTag tag) {
|
||||
result = Construction::getInstructionOperand(this, tag)
|
||||
final Operand getAUse() {
|
||||
result.getDefinitionInstruction() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all instructions consumed by this instruction's operands.
|
||||
* Gets all of this instruction's operands.
|
||||
*/
|
||||
final Instruction getAnOperand() {
|
||||
result = getOperand(_)
|
||||
final Operand getAnOperand() {
|
||||
result.getInstruction() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this instruction has a memory operand with the specified tag.
|
||||
*/
|
||||
final predicate isMemoryOperand(OperandTag tag) {
|
||||
exists(getOperandMemoryAccess(tag))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of memory access performed by the specified operand. Holds
|
||||
* only for memory operands.
|
||||
*/
|
||||
MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this instruction produces a memory result.
|
||||
*/
|
||||
@@ -461,9 +438,7 @@ class Instruction extends Construction::TInstruction {
|
||||
// Register results are always in SSA form.
|
||||
not hasMemoryResult() or
|
||||
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
|
||||
not exists(Instruction useInstr, UnmodeledUseOperand useTag |
|
||||
this = useInstr.getOperand(useTag)
|
||||
)
|
||||
not (getAUse() instanceof UnmodeledUseOperand)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -602,7 +577,7 @@ class FieldAddressInstruction extends FieldInstruction {
|
||||
}
|
||||
|
||||
final Instruction getObjectAddress() {
|
||||
result = getOperand(unaryOperand())
|
||||
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,12 +615,7 @@ class ReturnValueInstruction extends ReturnInstruction {
|
||||
}
|
||||
|
||||
final Instruction getReturnValue() {
|
||||
result = getOperand(returnValueOperand())
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(ReturnValueOperand))) and
|
||||
result instanceof IndirectMemoryAccess
|
||||
result = getAnOperand().(ReturnValueOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +625,7 @@ class CopyInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getSourceValue() {
|
||||
result = getOperand(copySourceOperand())
|
||||
result = getAnOperand().(CopySourceOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,13 +640,8 @@ class LoadInstruction extends CopyInstruction {
|
||||
opcode instanceof Opcode::Load
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(CopySourceOperand))) and
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
|
||||
final Instruction getSourceAddress() {
|
||||
result = getOperand(loadStoreAddressOperand())
|
||||
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,7 +655,7 @@ class StoreInstruction extends CopyInstruction {
|
||||
}
|
||||
|
||||
final Instruction getDestinationAddress() {
|
||||
result = getOperand(loadStoreAddressOperand())
|
||||
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,7 +665,7 @@ class ConditionalBranchInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getCondition() {
|
||||
result = getOperand(conditionOperand())
|
||||
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
final Instruction getTrueSuccessor() {
|
||||
@@ -758,11 +723,11 @@ class BinaryInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getLeftOperand() {
|
||||
result = getOperand(leftOperand())
|
||||
result = getAnOperand().(LeftOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
final Instruction getRightOperand() {
|
||||
result = getOperand(rightOperand())
|
||||
result = getAnOperand().(RightOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,7 +838,7 @@ class UnaryInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getOperand() {
|
||||
result = getOperand(unaryOperand())
|
||||
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -992,6 +957,7 @@ class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||
* of this relational instruction, that is, the side that is larger
|
||||
@@ -1011,6 +977,7 @@ class RelationalInstruction extends CompareInstruction {
|
||||
Instruction getLesserOperand() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
|
||||
*/
|
||||
@@ -1097,7 +1064,7 @@ class SwitchInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getExpression() {
|
||||
result = getOperand(conditionOperand())
|
||||
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
final Instruction getACaseSuccessor() {
|
||||
@@ -1117,7 +1084,7 @@ class CallInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getCallTarget() {
|
||||
result = getOperand(callTargetOperand())
|
||||
result = getAnOperand().(CallTargetOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1138,24 +1105,18 @@ class ThrowValueInstruction extends ThrowInstruction {
|
||||
opcode instanceof Opcode::ThrowValue
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(ExceptionOperand))) and
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the address of the exception thrown by this instruction.
|
||||
*/
|
||||
final Instruction getExceptionAddress() {
|
||||
result = getOperand(loadStoreAddressOperand())
|
||||
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exception thrown by this instruction.
|
||||
*/
|
||||
final Instruction getException() {
|
||||
result = getOperand(exceptionOperand())
|
||||
result = getAnOperand().(ExceptionOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,11 +1197,6 @@ class UnmodeledUseInstruction extends Instruction {
|
||||
override string getOperandsString() {
|
||||
result = "mu*"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(UnmodeledUseOperand))) and
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
class PhiInstruction extends Instruction {
|
||||
@@ -1248,11 +1204,6 @@ class PhiInstruction extends Instruction {
|
||||
opcode instanceof Opcode::Phi
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(PhiOperand))) and
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
|
||||
360
cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll
Normal file
360
cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll
Normal file
@@ -0,0 +1,360 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
|
||||
private newtype TOperand =
|
||||
TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getInstructionOperand(instr, tag)
|
||||
} or
|
||||
TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) {
|
||||
defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock)
|
||||
}
|
||||
|
||||
/**
|
||||
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
string toString() {
|
||||
result = "Operand"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
Instruction getInstruction() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand.
|
||||
*/
|
||||
Instruction getDefinitionInstruction() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a prefix to use when dumping the operand in an operand list.
|
||||
*/
|
||||
string getDumpLabel() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing this operand, suitable for display in IR dumps. This consists of the
|
||||
* result ID of the instruction consumed by the operand, plus a label identifying the operand
|
||||
* kind.
|
||||
*
|
||||
* For example: `this:r3_5`
|
||||
*/
|
||||
final string getDumpString() {
|
||||
result = getDumpLabel() + getDefinitionInstruction().getResultId()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order in which the operand should be sorted in the operand list.
|
||||
*/
|
||||
int getDumpSortOrder() {
|
||||
result = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of memory access performed by the operand. Holds only for memory operands.
|
||||
*/
|
||||
MemoryAccessKind getMemoryAccess() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the operand that holds the memory address from which the current operand loads its
|
||||
* value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2`
|
||||
* is `r1`.
|
||||
*/
|
||||
final AddressOperand getAddressOperand() {
|
||||
getMemoryAccess() instanceof IndirectMemoryAccess and
|
||||
result.getInstruction() = getInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand that is not an operand of a `PhiInstruction`.
|
||||
*/
|
||||
class NonPhiOperand extends Operand, TNonPhiOperand {
|
||||
Instruction instr;
|
||||
Instruction defInstr;
|
||||
OperandTag tag;
|
||||
|
||||
NonPhiOperand() {
|
||||
this = TNonPhiOperand(instr, tag, defInstr)
|
||||
}
|
||||
|
||||
override final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
|
||||
override final Instruction getDefinitionInstruction() {
|
||||
result = defInstr
|
||||
}
|
||||
|
||||
override final string getDumpLabel() {
|
||||
result = tag.getLabel()
|
||||
}
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = tag.getSortOrder()
|
||||
}
|
||||
|
||||
final OperandTag getOperandTag() {
|
||||
result = tag
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class AddressOperand extends NonPhiOperand {
|
||||
AddressOperand() {
|
||||
this = TNonPhiOperand(_, addressOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Address"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends NonPhiOperand {
|
||||
CopySourceOperand() {
|
||||
this = TNonPhiOperand(_, copySourceOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
instr.getOpcode() instanceof Opcode::Load and
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends NonPhiOperand {
|
||||
UnaryOperand() {
|
||||
this = TNonPhiOperand(_, unaryOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends NonPhiOperand {
|
||||
LeftOperand() {
|
||||
this = TNonPhiOperand(_, leftOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends NonPhiOperand {
|
||||
RightOperand() {
|
||||
this = TNonPhiOperand(_, rightOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends NonPhiOperand {
|
||||
ReturnValueOperand() {
|
||||
this = TNonPhiOperand(_, returnValueOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends NonPhiOperand {
|
||||
ExceptionOperand() {
|
||||
this = TNonPhiOperand(_, exceptionOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends NonPhiOperand {
|
||||
ConditionOperand() {
|
||||
this = TNonPhiOperand(_, conditionOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends NonPhiOperand {
|
||||
UnmodeledUseOperand() {
|
||||
this = TNonPhiOperand(_, unmodeledUseOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Call` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends NonPhiOperand {
|
||||
CallTargetOperand() {
|
||||
this = TNonPhiOperand(_, callTargetOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
class ArgumentOperand extends NonPhiOperand {
|
||||
ArgumentOperand() {
|
||||
exists(ArgumentOperandTag argTag |
|
||||
this = TNonPhiOperand(_, argTag, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TNonPhiOperand(_, thisArgumentOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "ThisArgument"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
exists(PositionalArgumentOperandTag argTag |
|
||||
this = TNonPhiOperand(_, argTag, _) and
|
||||
argIndex = argTag.getArgIndex()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
class PhiOperand extends Operand, TPhiOperand {
|
||||
PhiInstruction instr;
|
||||
Instruction defInstr;
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(instr, defInstr, predecessorBlock)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final PhiInstruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
|
||||
override final Instruction getDefinitionInstruction() {
|
||||
result = defInstr
|
||||
}
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getDumpLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the predecessor block from which this value comes.
|
||||
*/
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand that reads a value from memory.
|
||||
*/
|
||||
class MemoryOperand extends Operand {
|
||||
MemoryOperand() {
|
||||
exists(getMemoryAccess())
|
||||
}
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
|
||||
private newtype TOperandTag =
|
||||
TLoadStoreAddressOperand() or
|
||||
TCopySourceOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
TRightOperand() or
|
||||
TReturnValueOperand() or
|
||||
TExceptionOperand() or
|
||||
TConditionOperand() or
|
||||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
)
|
||||
} or
|
||||
TPhiOperand(IRBlock predecessorBlock) {
|
||||
exists(PhiInstruction phi |
|
||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
|
||||
abstract int getSortOrder();
|
||||
|
||||
string getLabel() {
|
||||
result = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||
override final string toString() {
|
||||
result = "LoadStoreAddress"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||
result = TLoadStoreAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||
override final string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
CopySourceOperand copySourceOperand() {
|
||||
result = TCopySourceOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOperand unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends OperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
}
|
||||
}
|
||||
|
||||
LeftOperand leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends OperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
}
|
||||
}
|
||||
|
||||
RightOperand rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||
override final string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValueOperand returnValueOperand() {
|
||||
result = TReturnValueOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOperand exceptionOperand() {
|
||||
result = TExceptionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
}
|
||||
}
|
||||
|
||||
ConditionOperand conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
}
|
||||
}
|
||||
|
||||
UnmodeledUseOperand unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Call` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
}
|
||||
}
|
||||
|
||||
CallTargetOperand callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperand extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(this)"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "this:"
|
||||
}
|
||||
}
|
||||
|
||||
ThisArgumentOperand thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand,
|
||||
TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + argIndex
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
}
|
||||
|
||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of an SSA `Phi` instruction.
|
||||
*/
|
||||
class PhiOperand extends OperandTag, TPhiOperand {
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
}
|
||||
|
||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||
result = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.raw.IR
|
||||
import IRBlockConstruction as BlockConstruction
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
@@ -37,14 +38,6 @@ cached private module Cached {
|
||||
exists(getTranslatedFunction(func))
|
||||
}
|
||||
|
||||
cached int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(FunctionCall call |
|
||||
exists(call.getArgument(argIndex))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached newtype TInstruction =
|
||||
MkInstruction(FunctionIR funcIR, Opcode opcode, Locatable ast,
|
||||
InstructionTag tag, Type resultType, boolean isGLValue) {
|
||||
@@ -98,6 +91,10 @@ cached private module Cached {
|
||||
instruction.getTag(), tag)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionOperand(Instruction instruction, IRBlock predecessorBlock) {
|
||||
none()
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
@@ -209,7 +210,7 @@ class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
|
||||
}
|
||||
|
||||
class TranslatedValueCondition extends TranslatedCondition,
|
||||
TTranslatedValueCondition {
|
||||
TTranslatedValueCondition {
|
||||
TranslatedValueCondition() {
|
||||
this = TTranslatedValueCondition(expr)
|
||||
}
|
||||
@@ -223,7 +224,7 @@ class TranslatedValueCondition extends TranslatedCondition,
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isGLValue) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
opcode instanceof Opcode::ConditionalBranch and
|
||||
resultType instanceof VoidType and
|
||||
@@ -236,7 +237,7 @@ class TranslatedValueCondition extends TranslatedCondition,
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
EdgeKind kind) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
(
|
||||
(
|
||||
@@ -251,9 +252,9 @@ class TranslatedValueCondition extends TranslatedCondition,
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
operandTag instanceof ConditionOperand and
|
||||
operandTag instanceof ConditionOperandTag and
|
||||
result = getValueExpr().getResult()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
@@ -157,7 +158,7 @@ class TranslatedUninitializedVariable extends
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.raw.IR
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
@@ -209,16 +210,16 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
(
|
||||
tag = ConditionValueTrueStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(ConditionValueTrueTempAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getInstruction(ConditionValueTrueConstantTag())
|
||||
)
|
||||
)
|
||||
@@ -227,11 +228,11 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
tag = ConditionValueFalseStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(ConditionValueFalseTempAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getInstruction(ConditionValueFalseConstantTag())
|
||||
)
|
||||
)
|
||||
@@ -240,11 +241,11 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
tag = ConditionValueResultLoadTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(ConditionValueResultTempAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
)
|
||||
@@ -315,7 +316,7 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isGLValue) {
|
||||
Type resultType, boolean isGLValue) {
|
||||
tag = LoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = expr.getType().getUnspecifiedType() and
|
||||
@@ -326,7 +327,7 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag,
|
||||
EdgeKind kind) {
|
||||
EdgeKind kind) {
|
||||
tag = LoadTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
@@ -345,11 +346,11 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
|
||||
tag = LoadTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getOperand().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
)
|
||||
@@ -404,7 +405,7 @@ class TranslatedCommaExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -478,16 +479,16 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
(
|
||||
tag = CrementLoadTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getOperand().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
)
|
||||
@@ -496,11 +497,11 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
tag = CrementOpTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LeftOperand and
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = getInstruction(CrementLoadTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof RightOperand and
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = getInstruction(CrementConstantTag())
|
||||
)
|
||||
)
|
||||
@@ -509,11 +510,11 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
|
||||
tag = CrementStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getOperand().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getInstruction(CrementOpTag())
|
||||
)
|
||||
)
|
||||
@@ -670,11 +671,11 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
||||
tag = OnlyInstructionTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LeftOperand and
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = getBaseOperand().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof RightOperand and
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = getOffsetOperand().getResult()
|
||||
)
|
||||
)
|
||||
@@ -722,7 +723,7 @@ abstract class TranslatedTransparentExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -804,7 +805,7 @@ class TranslatedThisExpr extends TranslatedNonConstantExpr {
|
||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getInitializeThisInstruction()
|
||||
}
|
||||
|
||||
@@ -857,7 +858,7 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -891,7 +892,7 @@ class TranslatedFieldAccess extends TranslatedVariableAccess {
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperand and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getQualifier().getResult()
|
||||
}
|
||||
|
||||
@@ -987,7 +988,7 @@ abstract class TranslatedConstantExpr extends TranslatedCoreExpr {
|
||||
}
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -1100,13 +1101,13 @@ class TranslatedUnaryExpr extends TranslatedSingleInstructionExpr {
|
||||
}
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = getOperand().getResult() and
|
||||
if getOpcode() instanceof Opcode::CopyValue then
|
||||
operandTag instanceof CopySourceOperand
|
||||
operandTag instanceof CopySourceOperandTag
|
||||
else
|
||||
operandTag instanceof UnaryOperand
|
||||
operandTag instanceof UnaryOperandTag
|
||||
}
|
||||
|
||||
override final Opcode getOpcode() {
|
||||
@@ -1172,9 +1173,9 @@ abstract class TranslatedSingleInstructionConversion extends TranslatedConversio
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperand and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getOperand().getResult()
|
||||
}
|
||||
|
||||
@@ -1313,11 +1314,11 @@ class TranslatedBoolConversion extends TranslatedConversion {
|
||||
tag = BoolConversionCompareTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LeftOperand and
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = getOperand().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof RightOperand and
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = getInstruction(BoolConversionConstantTag())
|
||||
)
|
||||
)
|
||||
@@ -1381,21 +1382,21 @@ class TranslatedBinaryOperation extends TranslatedSingleInstructionExpr {
|
||||
tag = OnlyInstructionTag() and
|
||||
if swapOperandsOnOp() then (
|
||||
(
|
||||
operandTag instanceof RightOperand and
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = getLeftOperand().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof LeftOperand and
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = getRightOperand().getResult()
|
||||
)
|
||||
)
|
||||
else (
|
||||
(
|
||||
operandTag instanceof LeftOperand and
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = getLeftOperand().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof RightOperand and
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = getRightOperand().getResult()
|
||||
)
|
||||
)
|
||||
@@ -1551,11 +1552,11 @@ class TranslatedAssignExpr extends TranslatedAssignment {
|
||||
tag = AssignmentStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getLeftOperand().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getRightOperand().getResult()
|
||||
)
|
||||
)
|
||||
@@ -1714,11 +1715,11 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
tag = AssignOperationLoadTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getLeftOperand().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
)
|
||||
@@ -1726,21 +1727,21 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
(
|
||||
leftOperandNeedsConversion() and
|
||||
tag = AssignOperationConvertLeftTag() and
|
||||
operandTag instanceof UnaryOperand and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getInstruction(AssignOperationLoadTag())
|
||||
) or
|
||||
(
|
||||
tag = AssignOperationOpTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LeftOperand and
|
||||
operandTag instanceof LeftOperandTag and
|
||||
if leftOperandNeedsConversion() then
|
||||
result = getInstruction(AssignOperationConvertLeftTag())
|
||||
else
|
||||
result = getInstruction(AssignOperationLoadTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof RightOperand and
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = getRightOperand().getResult()
|
||||
)
|
||||
)
|
||||
@@ -1748,18 +1749,18 @@ class TranslatedAssignOperation extends TranslatedAssignment {
|
||||
(
|
||||
leftOperandNeedsConversion() and
|
||||
tag = AssignOperationConvertResultTag() and
|
||||
operandTag instanceof UnaryOperand and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getInstruction(AssignOperationOpTag())
|
||||
) or
|
||||
(
|
||||
tag = AssignmentStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getLeftOperand().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getStoredValue()
|
||||
)
|
||||
)
|
||||
@@ -1828,14 +1829,14 @@ abstract class TranslatedCall extends TranslatedExpr {
|
||||
tag = CallTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof CallTargetOperand and
|
||||
operandTag instanceof CallTargetOperandTag and
|
||||
result = getCallTargetResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof ThisArgumentOperand and
|
||||
operandTag instanceof ThisArgumentOperandTag and
|
||||
result = getQualifierResult()
|
||||
) or
|
||||
exists(PositionalArgumentOperand argTag |
|
||||
exists(PositionalArgumentOperandTag argTag |
|
||||
argTag = operandTag and
|
||||
result = getArgument(argTag.getArgIndex()).getResult()
|
||||
)
|
||||
@@ -2071,13 +2072,13 @@ class TranslatedNonConstantAllocationSize extends TranslatedAllocationSize {
|
||||
(
|
||||
tag = AllocationSizeTag() and
|
||||
(
|
||||
operandTag instanceof LeftOperand and result = getInstruction(AllocationExtentConvertTag()) or
|
||||
operandTag instanceof RightOperand and result = getInstruction(AllocationElementSizeTag())
|
||||
operandTag instanceof LeftOperandTag and result = getInstruction(AllocationExtentConvertTag()) or
|
||||
operandTag instanceof RightOperandTag and result = getInstruction(AllocationElementSizeTag())
|
||||
)
|
||||
) or
|
||||
(
|
||||
tag = AllocationExtentConvertTag() and
|
||||
operandTag instanceof UnaryOperand and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getExtent().getResult()
|
||||
)
|
||||
}
|
||||
@@ -2322,7 +2323,7 @@ class TranslatedDestructorFieldDestruction extends TranslatedNonConstantExpr,
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperand and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getTranslatedFunction(destruction.getEnclosingFunction()).getInitializeThisInstruction()
|
||||
}
|
||||
|
||||
@@ -2433,7 +2434,7 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
not resultIsVoid() and
|
||||
(
|
||||
(
|
||||
@@ -2441,11 +2442,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||
tag = ConditionValueTrueStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(ConditionValueTrueTempAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getThen().getResult()
|
||||
)
|
||||
)
|
||||
@@ -2455,11 +2456,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||
tag = ConditionValueFalseStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(ConditionValueFalseTempAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getElse().getResult()
|
||||
)
|
||||
)
|
||||
@@ -2468,11 +2469,11 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr,
|
||||
tag = ConditionValueResultLoadTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(ConditionValueResultTempAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
)
|
||||
@@ -2648,11 +2649,11 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr,
|
||||
tag = ThrowTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof ExceptionOperand and
|
||||
operandTag instanceof ExceptionOperandTag and
|
||||
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
)
|
||||
@@ -2864,7 +2865,7 @@ abstract class TranslatedNewOrNewArrayExpr extends TranslatedNonConstantExpr,
|
||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperand and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getAllocatorCall().getResult()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.raw.IR
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
@@ -210,10 +211,10 @@ class TranslatedFunction extends TranslatedElement,
|
||||
}
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
(
|
||||
tag = UnmodeledUseTag() and
|
||||
operandTag instanceof UnmodeledUseOperand and
|
||||
operandTag instanceof UnmodeledUseOperandTag and
|
||||
result.getFunction() = func and
|
||||
result.hasMemoryResult()
|
||||
) or
|
||||
@@ -222,11 +223,11 @@ class TranslatedFunction extends TranslatedElement,
|
||||
not getReturnType() instanceof VoidType and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(ReturnValueAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof ReturnValueOperand and
|
||||
operandTag instanceof ReturnValueOperandTag and
|
||||
result = getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
)
|
||||
@@ -374,11 +375,11 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
|
||||
}
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(InitializerVariableAddressTag())
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
@@ -205,15 +206,15 @@ class TranslatedSimpleDirectInitialization extends
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getContext().getTargetAddress()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getInitializer().getResult()
|
||||
)
|
||||
)
|
||||
@@ -332,11 +333,11 @@ class TranslatedStringLiteralInitialization extends
|
||||
tag = InitializerLoadStringTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInitializer().getResult()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
|
||||
)
|
||||
)
|
||||
@@ -345,11 +346,11 @@ class TranslatedStringLiteralInitialization extends
|
||||
tag = InitializerStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getContext().getTargetAddress()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getInstruction(InitializerLoadStringTag())
|
||||
)
|
||||
)
|
||||
@@ -358,11 +359,11 @@ class TranslatedStringLiteralInitialization extends
|
||||
tag = ZeroPadStringElementAddressTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LeftOperand and
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = getContext().getTargetAddress()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof RightOperand and
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = getInstruction(ZeroPadStringElementIndexTag())
|
||||
)
|
||||
)
|
||||
@@ -371,11 +372,11 @@ class TranslatedStringLiteralInitialization extends
|
||||
tag = ZeroPadStringStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(ZeroPadStringElementAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getInstruction(ZeroPadStringConstantTag())
|
||||
)
|
||||
)
|
||||
@@ -450,7 +451,7 @@ class TranslatedConstructorInitialization extends
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -514,9 +515,9 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
tag = getFieldAddressTag() and
|
||||
operandTag instanceof UnaryOperand and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getParent().(InitializationContext).getTargetAddress()
|
||||
}
|
||||
|
||||
@@ -633,17 +634,17 @@ class TranslatedFieldValueInitialization extends
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
result = TranslatedFieldInitialization.super.getInstructionOperand(tag, operandTag) or
|
||||
(
|
||||
tag = getFieldDefaultValueStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(getFieldAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getInstruction(getFieldDefaultValueTag())
|
||||
)
|
||||
)
|
||||
@@ -723,15 +724,15 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
tag = getElementAddressTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LeftOperand and
|
||||
operandTag instanceof LeftOperandTag and
|
||||
result = getParent().(InitializationContext).getTargetAddress()
|
||||
) or
|
||||
(
|
||||
operandTag instanceof RightOperand and
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = getInstruction(getElementIndexTag())
|
||||
)
|
||||
)
|
||||
@@ -882,17 +883,17 @@ class TranslatedElementValueInitialization extends
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
result = TranslatedElementInitialization.super.getInstructionOperand(tag, operandTag) or
|
||||
(
|
||||
tag = getElementDefaultValueStoreTag() and
|
||||
(
|
||||
(
|
||||
operandTag instanceof LoadStoreAddressOperand and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = getInstruction(getElementAddressTag())
|
||||
) or
|
||||
(
|
||||
operandTag instanceof CopySourceOperand and
|
||||
operandTag instanceof CopySourceOperandTag and
|
||||
result = getInstruction(getElementDefaultValueTag())
|
||||
)
|
||||
)
|
||||
@@ -981,9 +982,9 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
|
||||
}
|
||||
|
||||
override final Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperand and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getTranslatedFunction(getFunction()).getInitializeThisInstruction()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
private import TranslatedDeclarationEntry
|
||||
@@ -732,7 +733,7 @@ class TranslatedSwitchStmt extends TranslatedStmt {
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
tag = SwitchBranchTag() and
|
||||
operandTag instanceof ConditionOperand and
|
||||
operandTag instanceof ConditionOperandTag and
|
||||
result = getExpr().getResult()
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import FunctionIR
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import IRVariable
|
||||
import OperandTag
|
||||
import Operand
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@ private import internal.IRInternal
|
||||
import FunctionIR
|
||||
import IRBlock
|
||||
import IRVariable
|
||||
import OperandTag
|
||||
import Operand
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.EdgeKind
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
|
||||
class InstructionTag = Construction::InstructionTagType;
|
||||
|
||||
@@ -22,21 +23,21 @@ module InstructionSanity {
|
||||
exists(Opcode opcode |
|
||||
opcode = instr.getOpcode() and
|
||||
(
|
||||
opcode instanceof UnaryOpcode and tag instanceof UnaryOperand or
|
||||
opcode instanceof UnaryOpcode and tag instanceof UnaryOperandTag or
|
||||
(
|
||||
opcode instanceof BinaryOpcode and
|
||||
(
|
||||
tag instanceof LeftOperand or
|
||||
tag instanceof RightOperand
|
||||
tag instanceof LeftOperandTag or
|
||||
tag instanceof RightOperandTag
|
||||
)
|
||||
) or
|
||||
opcode instanceof CopyOpcode and tag instanceof CopySourceOperand or
|
||||
opcode instanceof MemoryAccessOpcode and tag instanceof LoadStoreAddressOperand or
|
||||
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperand or
|
||||
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperand or
|
||||
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperand or
|
||||
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperand or
|
||||
opcode instanceof Opcode::Call and tag instanceof CallTargetOperand
|
||||
opcode instanceof CopyOpcode and tag instanceof CopySourceOperandTag or
|
||||
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or
|
||||
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag or
|
||||
opcode instanceof Opcode::ReturnValue and tag instanceof ReturnValueOperandTag or
|
||||
opcode instanceof Opcode::ThrowValue and tag instanceof ExceptionOperandTag or
|
||||
opcode instanceof Opcode::UnmodeledUse and tag instanceof UnmodeledUseOperandTag or
|
||||
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -45,26 +46,34 @@ module InstructionSanity {
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, OperandTag tag) {
|
||||
expectsOperand(instr, tag) and not exists(instr.getOperand(tag))
|
||||
expectsOperand(instr, tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag) and
|
||||
not expectsOperand(instr, tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperand) and
|
||||
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperand) and
|
||||
not (instr instanceof PhiInstruction and tag instanceof PhiOperand)
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
|
||||
strictcount(instr.getOperand(tag)) > 1 and
|
||||
not tag instanceof UnmodeledUseOperand
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
) > 1 and
|
||||
not tag instanceof UnmodeledUseOperandTag
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +83,7 @@ module InstructionSanity {
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiOperand operand |
|
||||
exists(instr.getOperand(operand)) and
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getPredecessorBlock() = pred
|
||||
)
|
||||
}
|
||||
@@ -98,14 +107,13 @@ module InstructionSanity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `op` consumes an operand `operand` that was defined in
|
||||
* Holds if operand `operand` consumes a value that was defined in
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(
|
||||
Instruction op, Instruction operand, OperandTag tag
|
||||
) {
|
||||
operand = op.getOperand(tag) and
|
||||
operand.getFunctionIR() != op.getFunctionIR()
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
operand.getInstruction() = instr and
|
||||
operand.getDefinitionInstruction() = defInstr and
|
||||
instr.getFunctionIR() != defInstr.getFunctionIR()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,20 +254,6 @@ class Instruction extends Construction::TInstruction {
|
||||
result = getResultId() + "(" + getResultTypeString() + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the specified operand, suitable for display in IR
|
||||
* dumps. This consists of the result ID of the instruction consumed by the
|
||||
* operand, plus a label identifying the operand kind.
|
||||
*
|
||||
* For example: `this:r3_5`
|
||||
*/
|
||||
string getOperandString(OperandTag tag) {
|
||||
exists(Instruction operand |
|
||||
operand = getOperand(tag) and
|
||||
result = tag.getLabel() + operand.getResultId()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing the operands of this instruction, suitable for
|
||||
* display in IR dumps.
|
||||
@@ -267,9 +261,9 @@ class Instruction extends Construction::TInstruction {
|
||||
* Example: `func:r3_4, this:r3_5`
|
||||
*/
|
||||
string getOperandsString() {
|
||||
result = concat(OperandTag tag, Instruction operand |
|
||||
operand = getOperand(tag) |
|
||||
tag.getLabel() + operand.getResultId(), ", " order by tag.getSortOrder()
|
||||
result = concat(Operand operand |
|
||||
operand = getAnOperand() |
|
||||
operand.getDumpString(), ", " order by operand.getDumpSortOrder()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -333,7 +327,6 @@ class Instruction extends Construction::TInstruction {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(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`.
|
||||
@@ -397,35 +390,19 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction that produced the value of the specified source
|
||||
* operand.
|
||||
* Gets all direct uses of the result of this instruction.
|
||||
*/
|
||||
final Instruction getOperand(OperandTag tag) {
|
||||
result = Construction::getInstructionOperand(this, tag)
|
||||
final Operand getAUse() {
|
||||
result.getDefinitionInstruction() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all instructions consumed by this instruction's operands.
|
||||
* Gets all of this instruction's operands.
|
||||
*/
|
||||
final Instruction getAnOperand() {
|
||||
result = getOperand(_)
|
||||
final Operand getAnOperand() {
|
||||
result.getInstruction() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this instruction has a memory operand with the specified tag.
|
||||
*/
|
||||
final predicate isMemoryOperand(OperandTag tag) {
|
||||
exists(getOperandMemoryAccess(tag))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of memory access performed by the specified operand. Holds
|
||||
* only for memory operands.
|
||||
*/
|
||||
MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this instruction produces a memory result.
|
||||
*/
|
||||
@@ -461,9 +438,7 @@ class Instruction extends Construction::TInstruction {
|
||||
// Register results are always in SSA form.
|
||||
not hasMemoryResult() or
|
||||
// An unmodeled result will have a use on the `UnmodeledUse` instruction.
|
||||
not exists(Instruction useInstr, UnmodeledUseOperand useTag |
|
||||
this = useInstr.getOperand(useTag)
|
||||
)
|
||||
not (getAUse() instanceof UnmodeledUseOperand)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -602,7 +577,7 @@ class FieldAddressInstruction extends FieldInstruction {
|
||||
}
|
||||
|
||||
final Instruction getObjectAddress() {
|
||||
result = getOperand(unaryOperand())
|
||||
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,12 +615,7 @@ class ReturnValueInstruction extends ReturnInstruction {
|
||||
}
|
||||
|
||||
final Instruction getReturnValue() {
|
||||
result = getOperand(returnValueOperand())
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(ReturnValueOperand))) and
|
||||
result instanceof IndirectMemoryAccess
|
||||
result = getAnOperand().(ReturnValueOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +625,7 @@ class CopyInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getSourceValue() {
|
||||
result = getOperand(copySourceOperand())
|
||||
result = getAnOperand().(CopySourceOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,13 +640,8 @@ class LoadInstruction extends CopyInstruction {
|
||||
opcode instanceof Opcode::Load
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(CopySourceOperand))) and
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
|
||||
final Instruction getSourceAddress() {
|
||||
result = getOperand(loadStoreAddressOperand())
|
||||
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,7 +655,7 @@ class StoreInstruction extends CopyInstruction {
|
||||
}
|
||||
|
||||
final Instruction getDestinationAddress() {
|
||||
result = getOperand(loadStoreAddressOperand())
|
||||
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,7 +665,7 @@ class ConditionalBranchInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getCondition() {
|
||||
result = getOperand(conditionOperand())
|
||||
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
final Instruction getTrueSuccessor() {
|
||||
@@ -758,11 +723,11 @@ class BinaryInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getLeftOperand() {
|
||||
result = getOperand(leftOperand())
|
||||
result = getAnOperand().(LeftOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
final Instruction getRightOperand() {
|
||||
result = getOperand(rightOperand())
|
||||
result = getAnOperand().(RightOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,7 +838,7 @@ class UnaryInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getOperand() {
|
||||
result = getOperand(unaryOperand())
|
||||
result = getAnOperand().(UnaryOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -992,6 +957,7 @@ class RelationalInstruction extends CompareInstruction {
|
||||
RelationalInstruction() {
|
||||
opcode instanceof RelationalOpcode
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand on the "greater" (or "greater-or-equal") side
|
||||
* of this relational instruction, that is, the side that is larger
|
||||
@@ -1011,6 +977,7 @@ class RelationalInstruction extends CompareInstruction {
|
||||
Instruction getLesserOperand() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this relational instruction is strict (is not an "or-equal" instruction).
|
||||
*/
|
||||
@@ -1097,7 +1064,7 @@ class SwitchInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getExpression() {
|
||||
result = getOperand(conditionOperand())
|
||||
result = getAnOperand().(ConditionOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
final Instruction getACaseSuccessor() {
|
||||
@@ -1117,7 +1084,7 @@ class CallInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getCallTarget() {
|
||||
result = getOperand(callTargetOperand())
|
||||
result = getAnOperand().(CallTargetOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1138,24 +1105,18 @@ class ThrowValueInstruction extends ThrowInstruction {
|
||||
opcode instanceof Opcode::ThrowValue
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(ExceptionOperand))) and
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the address of the exception thrown by this instruction.
|
||||
*/
|
||||
final Instruction getExceptionAddress() {
|
||||
result = getOperand(loadStoreAddressOperand())
|
||||
result = getAnOperand().(AddressOperand).getDefinitionInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exception thrown by this instruction.
|
||||
*/
|
||||
final Instruction getException() {
|
||||
result = getOperand(exceptionOperand())
|
||||
result = getAnOperand().(ExceptionOperand).getDefinitionInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,11 +1197,6 @@ class UnmodeledUseInstruction extends Instruction {
|
||||
override string getOperandsString() {
|
||||
result = "mu*"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(UnmodeledUseOperand))) and
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
class PhiInstruction extends Instruction {
|
||||
@@ -1248,11 +1204,6 @@ class PhiInstruction extends Instruction {
|
||||
opcode instanceof Opcode::Phi
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getOperandMemoryAccess(OperandTag tag) {
|
||||
exists(this.getOperand(tag.(PhiOperand))) and
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.implementation.MemoryAccessKind
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
|
||||
private newtype TOperand =
|
||||
TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getInstructionOperand(instr, tag)
|
||||
} or
|
||||
TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) {
|
||||
defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock)
|
||||
}
|
||||
|
||||
/**
|
||||
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
string toString() {
|
||||
result = "Operand"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
Instruction getInstruction() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand.
|
||||
*/
|
||||
Instruction getDefinitionInstruction() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a prefix to use when dumping the operand in an operand list.
|
||||
*/
|
||||
string getDumpLabel() {
|
||||
result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string describing this operand, suitable for display in IR dumps. This consists of the
|
||||
* result ID of the instruction consumed by the operand, plus a label identifying the operand
|
||||
* kind.
|
||||
*
|
||||
* For example: `this:r3_5`
|
||||
*/
|
||||
final string getDumpString() {
|
||||
result = getDumpLabel() + getDefinitionInstruction().getResultId()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order in which the operand should be sorted in the operand list.
|
||||
*/
|
||||
int getDumpSortOrder() {
|
||||
result = -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of memory access performed by the operand. Holds only for memory operands.
|
||||
*/
|
||||
MemoryAccessKind getMemoryAccess() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the operand that holds the memory address from which the current operand loads its
|
||||
* value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2`
|
||||
* is `r1`.
|
||||
*/
|
||||
final AddressOperand getAddressOperand() {
|
||||
getMemoryAccess() instanceof IndirectMemoryAccess and
|
||||
result.getInstruction() = getInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand that is not an operand of a `PhiInstruction`.
|
||||
*/
|
||||
class NonPhiOperand extends Operand, TNonPhiOperand {
|
||||
Instruction instr;
|
||||
Instruction defInstr;
|
||||
OperandTag tag;
|
||||
|
||||
NonPhiOperand() {
|
||||
this = TNonPhiOperand(instr, tag, defInstr)
|
||||
}
|
||||
|
||||
override final Instruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
|
||||
override final Instruction getDefinitionInstruction() {
|
||||
result = defInstr
|
||||
}
|
||||
|
||||
override final string getDumpLabel() {
|
||||
result = tag.getLabel()
|
||||
}
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = tag.getSortOrder()
|
||||
}
|
||||
|
||||
final OperandTag getOperandTag() {
|
||||
result = tag
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class AddressOperand extends NonPhiOperand {
|
||||
AddressOperand() {
|
||||
this = TNonPhiOperand(_, addressOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Address"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends NonPhiOperand {
|
||||
CopySourceOperand() {
|
||||
this = TNonPhiOperand(_, copySourceOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
instr.getOpcode() instanceof Opcode::Load and
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends NonPhiOperand {
|
||||
UnaryOperand() {
|
||||
this = TNonPhiOperand(_, unaryOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends NonPhiOperand {
|
||||
LeftOperand() {
|
||||
this = TNonPhiOperand(_, leftOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends NonPhiOperand {
|
||||
RightOperand() {
|
||||
this = TNonPhiOperand(_, rightOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends NonPhiOperand {
|
||||
ReturnValueOperand() {
|
||||
this = TNonPhiOperand(_, returnValueOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends NonPhiOperand {
|
||||
ExceptionOperand() {
|
||||
this = TNonPhiOperand(_, exceptionOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends NonPhiOperand {
|
||||
ConditionOperand() {
|
||||
this = TNonPhiOperand(_, conditionOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends NonPhiOperand {
|
||||
UnmodeledUseOperand() {
|
||||
this = TNonPhiOperand(_, unmodeledUseOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof UnmodeledMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Call` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends NonPhiOperand {
|
||||
CallTargetOperand() {
|
||||
this = TNonPhiOperand(_, callTargetOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
class ArgumentOperand extends NonPhiOperand {
|
||||
ArgumentOperand() {
|
||||
exists(ArgumentOperandTag argTag |
|
||||
this = TNonPhiOperand(_, argTag, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TNonPhiOperand(_, thisArgumentOperand(), _)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "ThisArgument"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
exists(PositionalArgumentOperandTag argTag |
|
||||
this = TNonPhiOperand(_, argTag, _) and
|
||||
argIndex = argTag.getArgIndex()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
class PhiOperand extends Operand, TPhiOperand {
|
||||
PhiInstruction instr;
|
||||
Instruction defInstr;
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(instr, defInstr, predecessorBlock)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final PhiInstruction getInstruction() {
|
||||
result = instr
|
||||
}
|
||||
|
||||
override final Instruction getDefinitionInstruction() {
|
||||
result = defInstr
|
||||
}
|
||||
|
||||
override final int getDumpSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getDumpLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the predecessor block from which this value comes.
|
||||
*/
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getMemoryAccess() {
|
||||
result instanceof PhiMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand that reads a value from memory.
|
||||
*/
|
||||
class MemoryOperand extends Operand {
|
||||
MemoryOperand() {
|
||||
exists(getMemoryAccess())
|
||||
}
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
|
||||
private newtype TOperandTag =
|
||||
TLoadStoreAddressOperand() or
|
||||
TCopySourceOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
TRightOperand() or
|
||||
TReturnValueOperand() or
|
||||
TExceptionOperand() or
|
||||
TConditionOperand() or
|
||||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
)
|
||||
} or
|
||||
TPhiOperand(IRBlock predecessorBlock) {
|
||||
exists(PhiInstruction phi |
|
||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
|
||||
abstract int getSortOrder();
|
||||
|
||||
string getLabel() {
|
||||
result = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||
override final string toString() {
|
||||
result = "LoadStoreAddress"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||
result = TLoadStoreAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||
override final string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
CopySourceOperand copySourceOperand() {
|
||||
result = TCopySourceOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOperand unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends OperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
}
|
||||
}
|
||||
|
||||
LeftOperand leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends OperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
}
|
||||
}
|
||||
|
||||
RightOperand rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||
override final string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValueOperand returnValueOperand() {
|
||||
result = TReturnValueOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOperand exceptionOperand() {
|
||||
result = TExceptionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
}
|
||||
}
|
||||
|
||||
ConditionOperand conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
}
|
||||
}
|
||||
|
||||
UnmodeledUseOperand unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Call` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
}
|
||||
}
|
||||
|
||||
CallTargetOperand callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperand extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(this)"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "this:"
|
||||
}
|
||||
}
|
||||
|
||||
ThisArgumentOperand thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand,
|
||||
TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + argIndex
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
}
|
||||
|
||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of an SSA `Phi` instruction.
|
||||
*/
|
||||
class PhiOperand extends OperandTag, TPhiOperand {
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
}
|
||||
|
||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||
result = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
@@ -46,18 +46,20 @@ private IntValue getFieldBitOffset(Field field) {
|
||||
* not result in any address held in that operand from escaping beyond the
|
||||
* instruction.
|
||||
*/
|
||||
predicate operandIsConsumedWithoutEscaping(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// The source/destination address of a Load/Store does not escape (but the
|
||||
// loaded/stored value could).
|
||||
tag instanceof LoadStoreAddressOperand or
|
||||
// Neither operand of a Compare escapes.
|
||||
instr instanceof CompareInstruction or
|
||||
// Neither operand of a PointerDiff escapes.
|
||||
instr instanceof PointerDiffInstruction or
|
||||
// Converting an address to a `bool` does not escape the address.
|
||||
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
||||
predicate operandIsConsumedWithoutEscaping(Operand operand) {
|
||||
// The source/destination address of a Load/Store does not escape (but the
|
||||
// loaded/stored value could).
|
||||
operand instanceof AddressOperand or
|
||||
exists (Instruction instr |
|
||||
instr = operand.getInstruction() and
|
||||
(
|
||||
// Neither operand of a Compare escapes.
|
||||
instr instanceof CompareInstruction or
|
||||
// Neither operand of a PointerDiff escapes.
|
||||
instr instanceof PointerDiffInstruction or
|
||||
// Converting an address to a `bool` does not escape the address.
|
||||
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,43 +98,44 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
|
||||
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
||||
* a constant, then `bitOffset` is unknown.
|
||||
*/
|
||||
predicate operandIsPropagated(Instruction instr, OperandTag tag,
|
||||
IntValue bitOffset) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
(
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
) or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
) or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
||||
exists(Instruction instr |
|
||||
instr = operand.getInstruction() and
|
||||
(
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
) or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, Type resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultType() and
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
) or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
) or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
(
|
||||
resultType instanceof PointerType or
|
||||
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
|
||||
) and
|
||||
bitOffset = 0
|
||||
) or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
||||
// A copy propagates the source value.
|
||||
tag instanceof CopySourceOperand and bitOffset = 0
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
) or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, Type resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultType() and
|
||||
(
|
||||
resultType instanceof PointerType or
|
||||
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
|
||||
) and
|
||||
bitOffset = 0
|
||||
) or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction)) or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
||||
// A copy propagates the source value.
|
||||
operand instanceof CopySourceOperand and bitOffset = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -140,16 +143,15 @@ predicate operandIsPropagated(Instruction instr, OperandTag tag,
|
||||
* Holds if any address held in operand number `tag` of instruction `instr`
|
||||
* escapes outside the domain of the analysis.
|
||||
*/
|
||||
predicate operandEscapes(Instruction instr, OperandTag tag) {
|
||||
exists(instr.getOperand(tag)) and
|
||||
predicate operandEscapes(Operand operand) {
|
||||
// Conservatively assume that the address escapes unless one of the following
|
||||
// holds:
|
||||
not (
|
||||
// The operand is used in a way that does not escape the instruction
|
||||
operandIsConsumedWithoutEscaping(instr, tag) or
|
||||
operandIsConsumedWithoutEscaping(operand) or
|
||||
// The address is propagated to the result of the instruction, but that
|
||||
// result does not itself escape.
|
||||
operandIsPropagated(instr, tag, _) and not resultEscapes(instr)
|
||||
operandIsPropagated(operand, _) and not resultEscapes(operand.getInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -159,10 +161,7 @@ predicate operandEscapes(Instruction instr, OperandTag tag) {
|
||||
*/
|
||||
predicate resultEscapes(Instruction instr) {
|
||||
// The result escapes if it has at least one use that escapes.
|
||||
exists(Instruction useInstr, OperandTag useOperandTag |
|
||||
useInstr.getOperand(useOperandTag) = instr and
|
||||
operandEscapes(useInstr, useOperandTag)
|
||||
)
|
||||
operandEscapes(instr.getAUse())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,12 +202,12 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
|
||||
instr.(VariableAddressInstruction).getVariable() = var and
|
||||
bitOffset = 0
|
||||
) or
|
||||
exists(OperandTag operandTag, IntValue originalBitOffset,
|
||||
IntValue propagatedBitOffset |
|
||||
exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset |
|
||||
operand = instr.getAnOperand() and
|
||||
// If an operand is propagated, then the result points to the same variable,
|
||||
// offset by the bit offset from the propagation.
|
||||
resultPointsTo(instr.getOperand(operandTag), var, originalBitOffset) and
|
||||
operandIsPropagated(instr, operandTag, propagatedBitOffset) and
|
||||
resultPointsTo(operand.getDefinitionInstruction(), var, originalBitOffset) and
|
||||
operandIsPropagated(operand, propagatedBitOffset) and
|
||||
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,30 +1,13 @@
|
||||
import SSAConstructionInternal
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
import NewIR
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import NewIR
|
||||
import IRBlockConstruction as BlockConstruction
|
||||
|
||||
import Cached
|
||||
cached private module Cached {
|
||||
|
||||
private OldIR::OperandTag getOldOperandTag(OperandTag newTag) {
|
||||
newTag instanceof LoadStoreAddressOperand and result instanceof OldIR::LoadStoreAddressOperand or
|
||||
newTag instanceof CopySourceOperand and result instanceof OldIR::CopySourceOperand or
|
||||
newTag instanceof UnaryOperand and result instanceof OldIR::UnaryOperand or
|
||||
newTag instanceof LeftOperand and result instanceof OldIR::LeftOperand or
|
||||
newTag instanceof RightOperand and result instanceof OldIR::RightOperand or
|
||||
newTag instanceof ReturnValueOperand and result instanceof OldIR::ReturnValueOperand or
|
||||
newTag instanceof ExceptionOperand and result instanceof OldIR::ExceptionOperand or
|
||||
newTag instanceof ConditionOperand and result instanceof OldIR::ConditionOperand or
|
||||
newTag instanceof UnmodeledUseOperand and result instanceof OldIR::UnmodeledUseOperand or
|
||||
newTag instanceof CallTargetOperand and result instanceof OldIR::CallTargetOperand or
|
||||
newTag instanceof ThisArgumentOperand and result instanceof OldIR::ThisArgumentOperand or
|
||||
exists(PositionalArgumentOperand newArg |
|
||||
newArg = newTag and
|
||||
result.(OldIR::PositionalArgumentOperand).getArgIndex() = newArg.getArgIndex()
|
||||
)
|
||||
}
|
||||
|
||||
private IRBlock getNewBlock(OldIR::IRBlock oldBlock) {
|
||||
result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction())
|
||||
}
|
||||
@@ -49,14 +32,6 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(OldIR::PositionalArgumentOperand oldOperand |
|
||||
argIndex = oldOperand.getArgIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached OldIR::Instruction getOldInstruction(Instruction instr) {
|
||||
instr.getTag() = WrappedInstructionTag(result)
|
||||
}
|
||||
@@ -136,17 +111,18 @@ cached private module Cached {
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
exists(OldIR::Instruction oldUse, OldIR::OperandTag oldTag |
|
||||
oldUse = getOldInstruction(instruction) and
|
||||
oldTag = getOldOperandTag(tag) and
|
||||
if oldUse.isMemoryOperand(oldTag) then (
|
||||
exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
oldOperand = oldInstruction.getAnOperand() and
|
||||
tag = oldOperand.getOperandTag() and
|
||||
if oldOperand instanceof OldIR::MemoryOperand then (
|
||||
(
|
||||
if exists(Alias::getOperandMemoryAccess(oldUse, oldTag)) then (
|
||||
if exists(Alias::getOperandMemoryAccess(oldOperand)) then (
|
||||
exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex |
|
||||
vvar = Alias::getOperandMemoryAccess(oldUse, oldTag).getVirtualVariable() and
|
||||
vvar = Alias::getOperandMemoryAccess(oldOperand).getVirtualVariable() and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldUse) and
|
||||
hasUseAtRank(vvar, useBlock, useRank, oldInstruction) and
|
||||
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
|
||||
if defIndex >= 0 then
|
||||
result = getNewInstruction(defBlock.getInstruction(defIndex))
|
||||
@@ -162,25 +138,24 @@ cached private module Cached {
|
||||
// `UnmodeledUse` instruction.
|
||||
exists(OldIR::Instruction oldDefinition |
|
||||
instruction instanceof UnmodeledUseInstruction and
|
||||
tag instanceof UnmodeledUseOperand and
|
||||
oldDefinition = oldUse.getOperand(oldTag) and
|
||||
tag instanceof UnmodeledUseOperandTag and
|
||||
oldDefinition = oldOperand.getDefinitionInstruction() and
|
||||
not exists(Alias::getResultMemoryAccess(oldDefinition)) and
|
||||
result = getNewInstruction(oldDefinition)
|
||||
)
|
||||
)
|
||||
else
|
||||
result = getNewInstruction(oldUse.getOperand(oldTag))
|
||||
) or
|
||||
result = getPhiInstructionOperand(instruction.(PhiInstruction), tag.(PhiOperand))
|
||||
result = getNewInstruction(oldOperand.getDefinitionInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionOperand(PhiInstruction instr, PhiOperand tag) {
|
||||
cached Instruction getPhiInstructionOperand(PhiInstruction instr, IRBlock newPredecessorBlock) {
|
||||
exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock,
|
||||
OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock |
|
||||
hasPhiNode(vvar, phiBlock) and
|
||||
predBlock = phiBlock.getAPredecessor() and
|
||||
instr.getTag() = PhiTag(vvar, phiBlock) and
|
||||
tag.getPredecessorBlock() = getNewBlock(predBlock) and
|
||||
newPredecessorBlock = getNewBlock(predBlock) and
|
||||
hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and
|
||||
definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and
|
||||
if defIndex >= 0 then
|
||||
@@ -277,7 +252,7 @@ cached private module Cached {
|
||||
private predicate hasUse(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction use, OldIR::IRBlock block, int index) {
|
||||
exists(Alias::MemoryAccess access |
|
||||
access = Alias::getOperandMemoryAccess(use, _) and
|
||||
access = Alias::getOperandMemoryAccess(use.getAnOperand()) and
|
||||
block.getInstruction(index) = use and
|
||||
vvar = access.getVirtualVariable()
|
||||
)
|
||||
|
||||
@@ -2,7 +2,8 @@ import SimpleSSAInternal
|
||||
import cpp
|
||||
import Alias
|
||||
private import InputIR
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.Overlap
|
||||
|
||||
private newtype TVirtualVariable =
|
||||
MkVirtualVariable(IRVariable var) {
|
||||
@@ -69,15 +70,15 @@ Overlap getOverlap(MemoryAccess def, MemoryAccess use) {
|
||||
MemoryAccess getResultMemoryAccess(Instruction instr) {
|
||||
exists(IRVariable var |
|
||||
instr.getResultMemoryAccess() instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
resultPointsTo(instr.getAnOperand().(AddressOperand).getDefinitionInstruction(),
|
||||
var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
|
||||
MemoryAccess getOperandMemoryAccess(Instruction instr, OperandTag tag) {
|
||||
MemoryAccess getOperandMemoryAccess(Operand operand) {
|
||||
exists(IRVariable var |
|
||||
instr.getOperandMemoryAccess(tag) instanceof IndirectMemoryAccess and
|
||||
resultPointsTo(instr.getOperand(loadStoreAddressOperand()), var, 0) and
|
||||
resultPointsTo(operand.getAddressOperand().getDefinitionInstruction(), var, 0) and
|
||||
result = getMemoryAccess(var)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import cpp
|
||||
|
||||
private int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(FunctionCall call |
|
||||
exists(call.getArgument(argIndex))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TOperandTag =
|
||||
TLoadStoreAddressOperand() or
|
||||
TAddressOperand() or
|
||||
TCopySourceOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
@@ -16,15 +21,10 @@ private newtype TOperandTag =
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..Construction::getMaxCallArgIndex()] or
|
||||
argIndex in [0..getMaxCallArgIndex()] or
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
)
|
||||
} or
|
||||
TPhiOperand(IRBlock predecessorBlock) {
|
||||
exists(PhiInstruction phi |
|
||||
predecessorBlock = Construction::getPhiInstructionBlockStart(phi).getBlock().getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,9 +49,9 @@ abstract class OperandTag extends TOperandTag {
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
*/
|
||||
class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||
class AddressOperandTag extends OperandTag, TAddressOperand {
|
||||
override final string toString() {
|
||||
result = "LoadStoreAddress"
|
||||
result = "Address"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
@@ -59,15 +59,15 @@ class LoadStoreAddressOperand extends OperandTag, TLoadStoreAddressOperand {
|
||||
}
|
||||
}
|
||||
|
||||
LoadStoreAddressOperand loadStoreAddressOperand() {
|
||||
result = TLoadStoreAddressOperand()
|
||||
AddressOperandTag addressOperand() {
|
||||
result = TAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
*/
|
||||
class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||
class CopySourceOperandTag extends OperandTag, TCopySourceOperand {
|
||||
override final string toString() {
|
||||
result = "CopySource"
|
||||
}
|
||||
@@ -77,14 +77,14 @@ class CopySourceOperand extends OperandTag, TCopySourceOperand {
|
||||
}
|
||||
}
|
||||
|
||||
CopySourceOperand copySourceOperand() {
|
||||
CopySourceOperandTag copySourceOperand() {
|
||||
result = TCopySourceOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`).
|
||||
*/
|
||||
class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||
class UnaryOperandTag extends OperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
@@ -94,14 +94,14 @@ class UnaryOperand extends OperandTag, TUnaryOperand {
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOperand unaryOperand() {
|
||||
UnaryOperandTag unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperand extends OperandTag, TLeftOperand {
|
||||
class LeftOperandTag extends OperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
@@ -111,14 +111,14 @@ class LeftOperand extends OperandTag, TLeftOperand {
|
||||
}
|
||||
}
|
||||
|
||||
LeftOperand leftOperand() {
|
||||
LeftOperandTag leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperand extends OperandTag, TRightOperand {
|
||||
class RightOperandTag extends OperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
@@ -128,14 +128,14 @@ class RightOperand extends OperandTag, TRightOperand {
|
||||
}
|
||||
}
|
||||
|
||||
RightOperand rightOperand() {
|
||||
RightOperandTag rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The return value operand of a `ReturnValue` instruction.
|
||||
*/
|
||||
class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||
class ReturnValueOperandTag extends OperandTag, TReturnValueOperand {
|
||||
override final string toString() {
|
||||
result = "ReturnValue"
|
||||
}
|
||||
@@ -145,14 +145,14 @@ class ReturnValueOperand extends OperandTag, TReturnValueOperand {
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValueOperand returnValueOperand() {
|
||||
ReturnValueOperandTag returnValueOperand() {
|
||||
result = TReturnValueOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The exception thrown by a `ThrowValue` instruction.
|
||||
*/
|
||||
class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||
class ExceptionOperandTag extends OperandTag, TExceptionOperand {
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
@@ -162,14 +162,14 @@ class ExceptionOperand extends OperandTag, TExceptionOperand {
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOperand exceptionOperand() {
|
||||
ExceptionOperandTag exceptionOperand() {
|
||||
result = TExceptionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperand extends OperandTag, TConditionOperand {
|
||||
class ConditionOperandTag extends OperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
@@ -179,7 +179,7 @@ class ConditionOperand extends OperandTag, TConditionOperand {
|
||||
}
|
||||
}
|
||||
|
||||
ConditionOperand conditionOperand() {
|
||||
ConditionOperandTag conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ ConditionOperand conditionOperand() {
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||
class UnmodeledUseOperandTag extends OperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
@@ -197,14 +197,14 @@ class UnmodeledUseOperand extends OperandTag, TUnmodeledUseOperand {
|
||||
}
|
||||
}
|
||||
|
||||
UnmodeledUseOperand unmodeledUseOperand() {
|
||||
UnmodeledUseOperandTag unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Call` instruction.
|
||||
*/
|
||||
class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||
class CallTargetOperandTag extends OperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
@@ -214,7 +214,7 @@ class CallTargetOperand extends OperandTag, TCallTargetOperand {
|
||||
}
|
||||
}
|
||||
|
||||
CallTargetOperand callTargetOperand() {
|
||||
CallTargetOperandTag callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
|
||||
@@ -223,15 +223,15 @@ CallTargetOperand callTargetOperand() {
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperand extends OperandTag {
|
||||
abstract class ArgumentOperandTag extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||
ThisArgumentOperand() {
|
||||
class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand {
|
||||
ThisArgumentOperandTag() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
@@ -248,18 +248,18 @@ class ThisArgumentOperand extends ArgumentOperand, TThisArgumentOperand {
|
||||
}
|
||||
}
|
||||
|
||||
ThisArgumentOperand thisArgumentOperand() {
|
||||
ThisArgumentOperandTag thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperand extends ArgumentOperand,
|
||||
class PositionalArgumentOperandTag extends ArgumentOperandTag,
|
||||
TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperand() {
|
||||
PositionalArgumentOperandTag() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
@@ -276,37 +276,6 @@ class PositionalArgumentOperand extends ArgumentOperand,
|
||||
}
|
||||
}
|
||||
|
||||
PositionalArgumentOperand positionalArgumentOperand(int argIndex) {
|
||||
PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of an SSA `Phi` instruction.
|
||||
*/
|
||||
class PhiOperand extends OperandTag, TPhiOperand {
|
||||
IRBlock predecessorBlock;
|
||||
|
||||
PhiOperand() {
|
||||
this = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + getPredecessorBlock().getDisplayIndex()
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||
}
|
||||
|
||||
final IRBlock getPredecessorBlock() {
|
||||
result = predecessorBlock
|
||||
}
|
||||
}
|
||||
|
||||
PhiOperand phiOperand(IRBlock predecessorBlock) {
|
||||
result = TPhiOperand(predecessorBlock)
|
||||
}
|
||||
@@ -19,8 +19,8 @@ IntValue getConstantValue(Instruction instr) {
|
||||
result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or
|
||||
exists(PhiInstruction phi |
|
||||
phi = instr and
|
||||
result = max(Instruction operand | operand = phi.getAnOperand() | getConstantValue(operand)) and
|
||||
result = min(Instruction operand | operand = phi.getAnOperand() | getConstantValue(operand))
|
||||
result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and
|
||||
result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction()))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user