mirror of
https://github.com/github/codeql.git
synced 2026-04-26 09:15:12 +02:00
Merge pull request #352 from dave-bartolomeo/dave/Operands
C++: Operands as IPA types
This commit is contained in:
@@ -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::getInstructionOperandDefinition(instr, tag)
|
||||
} or
|
||||
TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) {
|
||||
defInstr = Construction::getPhiInstructionOperandDefinition(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)
|
||||
}
|
||||
@@ -135,18 +110,19 @@ cached private module Cached {
|
||||
instruction instanceof PhiInstruction // Phis always have modeled results
|
||||
}
|
||||
|
||||
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 (
|
||||
cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) {
|
||||
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,25 @@ 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 getPhiInstructionOperandDefinition(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 +253,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::getInstructionOperandDefinition(instr, tag)
|
||||
} or
|
||||
TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) {
|
||||
defInstr = Construction::getPhiInstructionOperandDefinition(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) {
|
||||
@@ -93,11 +86,16 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) {
|
||||
cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionOperand(
|
||||
instruction.getTag(), tag)
|
||||
}
|
||||
|
||||
cached Instruction getPhiInstructionOperandDefinition(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::getInstructionOperandDefinition(instr, tag)
|
||||
} or
|
||||
TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) {
|
||||
defInstr = Construction::getPhiInstructionOperandDefinition(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)
|
||||
}
|
||||
@@ -135,18 +110,19 @@ cached private module Cached {
|
||||
instruction instanceof PhiInstruction // Phis always have modeled results
|
||||
}
|
||||
|
||||
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 (
|
||||
cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) {
|
||||
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,25 @@ 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 getPhiInstructionOperandDefinition(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 +253,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)
|
||||
}
|
||||
Reference in New Issue
Block a user