From f278f4fa47d180fe7b48afe3d28335753b30b9be Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Tue, 23 Oct 2018 14:17:17 -0700 Subject: [PATCH 1/2] C++: Operands as IPA types @rdmarsh2 has been working on various queries and libraries on top of the IR, and has pointed out that having to always refer to an operand of an instruction by the pair of (instruction, operandTag) makes using the IR a bit clunky. This PR adds a new `Operand` IPA type that represents an operand of an instruction. `OperandTag` still exists, but is now an internal type used only in the IR implementation. --- config/identical-files.json | 8 +- .../ir/implementation/MemoryAccessKind.qll | 2 +- .../cpp/ir/implementation/aliased_ssa/IR.qll | 2 +- .../aliased_ssa/Instruction.qll | 165 +++----- .../ir/implementation/aliased_ssa/Operand.qll | 360 ++++++++++++++++++ .../aliased_ssa/internal/AliasAnalysis.qll | 117 +++--- .../aliased_ssa/internal/SSAConstruction.qll | 59 +-- .../aliased_ssa/internal/SimpleSSA.qll | 11 +- .../code/cpp/ir/implementation/raw/IR.qll | 2 +- .../cpp/ir/implementation/raw/Instruction.qll | 165 +++----- .../cpp/ir/implementation/raw/Operand.qll | 360 ++++++++++++++++++ .../cpp/ir/implementation/raw/OperandTag.qll | 312 --------------- .../raw/internal/IRConstruction.qll | 13 +- .../raw/internal/TranslatedCondition.qll | 11 +- .../internal/TranslatedDeclarationEntry.qll | 3 +- .../raw/internal/TranslatedElement.qll | 1 + .../raw/internal/TranslatedExpr.qll | 129 +++---- .../raw/internal/TranslatedFunction.qll | 13 +- .../raw/internal/TranslatedInitialization.qll | 51 +-- .../raw/internal/TranslatedStmt.qll | 3 +- .../ir/implementation/unaliased_ssa/IR.qll | 2 +- .../unaliased_ssa/Instruction.qll | 165 +++----- .../implementation/unaliased_ssa/Operand.qll | 360 ++++++++++++++++++ .../unaliased_ssa/OperandTag.qll | 312 --------------- .../unaliased_ssa/internal/AliasAnalysis.qll | 117 +++--- .../internal/SSAConstruction.qll | 59 +-- .../unaliased_ssa/internal/SimpleSSA.qll | 11 +- .../aliased_ssa => internal}/OperandTag.qll | 109 ++---- .../ir/constant_func/constant_func.ql | 4 +- 29 files changed, 1579 insertions(+), 1347 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll delete mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/raw/OperandTag.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll delete mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/OperandTag.qll rename cpp/ql/src/semmle/code/cpp/ir/{implementation/aliased_ssa => internal}/OperandTag.qll (64%) diff --git a/config/identical-files.json b/config/identical-files.json index 829837ceed40..1a7813948ce5 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -19,10 +19,10 @@ "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/FunctionIR.qll", "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/FunctionIR.qll" ], - "C++ IR OperandTag": [ - "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/OperandTag.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/OperandTag.qll", - "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/OperandTag.qll" + "C++ IR Operand": [ + "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll", + "cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll" ], "C++ IR IRImpl": [ "cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll", diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll index 2fdc6050ae4a..6cfa61861ff8 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll @@ -16,7 +16,7 @@ class MemoryAccessKind extends TMemoryAccessKind { /** * The operand or result accesses memory at the address specified by the - * `LoadStoreAddressOperand` on the same instruction. + * `AddressOperand` on the same instruction. */ class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess { override string toString() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll index 5e84762e7eb8..3fc7e0691258 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll @@ -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 diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 4603cf498481..c95cb23814e6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -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. - */ - final Instruction getOperand(OperandTag tag) { - result = Construction::getInstructionOperand(this, tag) - } - - /** - * Gets all instructions consumed by this instruction's operands. + * Gets all direct uses of the result of this instruction. */ - final Instruction getAnOperand() { - result = getOperand(_) + final Operand getAUse() { + result.getDefinitionInstruction() = this } /** - * Holds if this instruction has a memory operand with the specified tag. + * Gets all of this instruction's operands. */ - final predicate isMemoryOperand(OperandTag tag) { - exists(getOperandMemoryAccess(tag)) + final Operand getAnOperand() { + result.getInstruction() = this } - /** - * 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 } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll new file mode 100644 index 000000000000..ab0f60fc3183 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -0,0 +1,360 @@ +private import internal.IRInternal +import Instruction +import IRBlock +import cpp +import semmle.code.cpp.ir.implementation.MemoryAccessKind +private import semmle.code.cpp.ir.internal.OperandTag + +private newtype TOperand = + TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) { + defInstr = Construction::getInstructionOperand(instr, tag) + } or + TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) { + defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock) + } + +/** + * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. + */ +class Operand extends TOperand { + string toString() { + result = "Operand" + } + + /** + * Gets the `Instruction` that consumes this operand. + */ + Instruction getInstruction() { + none() + } + + /** + * Gets the `Instruction` whose result is the value of the operand. + */ + Instruction getDefinitionInstruction() { + none() + } + + /** + * Gets a prefix to use when dumping the operand in an operand list. + */ + string getDumpLabel() { + result = "" + } + + /** + * Gets a string describing this operand, suitable for display in IR dumps. This consists of the + * result ID of the instruction consumed by the operand, plus a label identifying the operand + * kind. + * + * For example: `this:r3_5` + */ + final string getDumpString() { + result = getDumpLabel() + getDefinitionInstruction().getResultId() + } + + /** + * Get the order in which the operand should be sorted in the operand list. + */ + int getDumpSortOrder() { + result = -1 + } + + /** + * Gets the kind of memory access performed by the operand. Holds only for memory operands. + */ + MemoryAccessKind getMemoryAccess() { + none() + } + + /** + * Returns the operand that holds the memory address from which the current operand loads its + * value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2` + * is `r1`. + */ + final AddressOperand getAddressOperand() { + getMemoryAccess() instanceof IndirectMemoryAccess and + result.getInstruction() = getInstruction() + } +} + +/** + * An operand that is not an operand of a `PhiInstruction`. + */ +class NonPhiOperand extends Operand, TNonPhiOperand { + Instruction instr; + Instruction defInstr; + OperandTag tag; + + NonPhiOperand() { + this = TNonPhiOperand(instr, tag, defInstr) + } + + override final Instruction getInstruction() { + result = instr + } + + override final Instruction getDefinitionInstruction() { + result = defInstr + } + + override final string getDumpLabel() { + result = tag.getLabel() + } + + override final int getDumpSortOrder() { + result = tag.getSortOrder() + } + + final OperandTag getOperandTag() { + result = tag + } +} + +/** + * The address operand of an instruction that loads or stores a value from + * memory (e.g. `Load`, `Store`). + */ +class AddressOperand extends NonPhiOperand { + AddressOperand() { + this = TNonPhiOperand(_, addressOperand(), _) + } + + override string toString() { + result = "Address" + } +} + +/** + * The source value operand of an instruction that copies this value to its + * result (e.g. `Copy`, `Load`, `Store`). + */ +class CopySourceOperand extends NonPhiOperand { + CopySourceOperand() { + this = TNonPhiOperand(_, copySourceOperand(), _) + } + + override string toString() { + result = "CopySource" + } + + override final MemoryAccessKind getMemoryAccess() { + instr.getOpcode() instanceof Opcode::Load and + result instanceof IndirectMemoryAccess + } +} + +/** + * The sole operand of a unary instruction (e.g. `Convert`, `Negate`). + */ +class UnaryOperand extends NonPhiOperand { + UnaryOperand() { + this = TNonPhiOperand(_, unaryOperand(), _) + } + + override string toString() { + result = "Unary" + } +} + +/** + * The left operand of a binary instruction (e.g. `Add`, `CompareEQ`). + */ +class LeftOperand extends NonPhiOperand { + LeftOperand() { + this = TNonPhiOperand(_, leftOperand(), _) + } + + override string toString() { + result = "Left" + } +} + +/** + * The right operand of a binary instruction (e.g. `Add`, `CompareEQ`). + */ +class RightOperand extends NonPhiOperand { + RightOperand() { + this = TNonPhiOperand(_, rightOperand(), _) + } + + override string toString() { + result = "Right" + } +} + +/** + * The return value operand of a `ReturnValue` instruction. + */ +class ReturnValueOperand extends NonPhiOperand { + ReturnValueOperand() { + this = TNonPhiOperand(_, returnValueOperand(), _) + } + + override string toString() { + result = "ReturnValue" + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof IndirectMemoryAccess + } +} + +/** + * The exception thrown by a `ThrowValue` instruction. + */ +class ExceptionOperand extends NonPhiOperand { + ExceptionOperand() { + this = TNonPhiOperand(_, exceptionOperand(), _) + } + + override string toString() { + result = "Exception" + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof IndirectMemoryAccess + } +} + +/** + * The condition operand of a `ConditionalBranch` or `Switch` instruction. + */ +class ConditionOperand extends NonPhiOperand { + ConditionOperand() { + this = TNonPhiOperand(_, conditionOperand(), _) + } + + override string toString() { + result = "Condition" + } +} + +/** + * An operand of the special `UnmodeledUse` instruction, representing a value + * whose set of uses is unknown. + */ +class UnmodeledUseOperand extends NonPhiOperand { + UnmodeledUseOperand() { + this = TNonPhiOperand(_, unmodeledUseOperand(), _) + } + + override string toString() { + result = "UnmodeledUse" + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof UnmodeledMemoryAccess + } +} + +/** + * The operand representing the target function of an `Call` instruction. + */ +class CallTargetOperand extends NonPhiOperand { + CallTargetOperand() { + this = TNonPhiOperand(_, callTargetOperand(), _) + } + + override string toString() { + result = "CallTarget" + } +} + +/** + * An operand representing an argument to a function call. This includes both + * positional arguments (represented by `PositionalArgumentOperand`) and the + * implicit `this` argument, if any (represented by `ThisArgumentOperand`). + */ +class ArgumentOperand extends NonPhiOperand { + ArgumentOperand() { + exists(ArgumentOperandTag argTag | + this = TNonPhiOperand(_, argTag, _) + ) + } +} + +/** + * An operand representing the implicit 'this' argument to a member function + * call. + */ +class ThisArgumentOperand extends ArgumentOperand { + ThisArgumentOperand() { + this = TNonPhiOperand(_, thisArgumentOperand(), _) + } + + override string toString() { + result = "ThisArgument" + } +} + +/** + * An operand representing an argument to a function call. + */ +class PositionalArgumentOperand extends ArgumentOperand { + int argIndex; + + PositionalArgumentOperand() { + exists(PositionalArgumentOperandTag argTag | + this = TNonPhiOperand(_, argTag, _) and + argIndex = argTag.getArgIndex() + ) + } + + override string toString() { + result = "Arg(" + argIndex + ")" + } +} + +/** + * An operand of a `PhiInstruction`. + */ +class PhiOperand extends Operand, TPhiOperand { + PhiInstruction instr; + Instruction defInstr; + IRBlock predecessorBlock; + + PhiOperand() { + this = TPhiOperand(instr, defInstr, predecessorBlock) + } + + override string toString() { + result = "Phi" + } + + override final PhiInstruction getInstruction() { + result = instr + } + + override final Instruction getDefinitionInstruction() { + result = defInstr + } + + override final int getDumpSortOrder() { + result = 11 + getPredecessorBlock().getDisplayIndex() + } + + override final string getDumpLabel() { + result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" + } + + /** + * Gets the predecessor block from which this value comes. + */ + final IRBlock getPredecessorBlock() { + result = predecessorBlock + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof PhiMemoryAccess + } +} + +/** + * An operand that reads a value from memory. + */ +class MemoryOperand extends Operand { + MemoryOperand() { + exists(getMemoryAccess()) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index f3be51b63d2d..fb897afa58d6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -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) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 70af6ce64138..ebd9952d7d2b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -1,30 +1,13 @@ import SSAConstructionInternal import cpp private import semmle.code.cpp.ir.implementation.Opcode -import NewIR +private import semmle.code.cpp.ir.internal.OperandTag +private import NewIR import IRBlockConstruction as BlockConstruction import Cached cached private module Cached { - private OldIR::OperandTag getOldOperandTag(OperandTag newTag) { - newTag instanceof LoadStoreAddressOperand and result instanceof OldIR::LoadStoreAddressOperand or - newTag instanceof CopySourceOperand and result instanceof OldIR::CopySourceOperand or - newTag instanceof UnaryOperand and result instanceof OldIR::UnaryOperand or - newTag instanceof LeftOperand and result instanceof OldIR::LeftOperand or - newTag instanceof RightOperand and result instanceof OldIR::RightOperand or - newTag instanceof ReturnValueOperand and result instanceof OldIR::ReturnValueOperand or - newTag instanceof ExceptionOperand and result instanceof OldIR::ExceptionOperand or - newTag instanceof ConditionOperand and result instanceof OldIR::ConditionOperand or - newTag instanceof UnmodeledUseOperand and result instanceof OldIR::UnmodeledUseOperand or - newTag instanceof CallTargetOperand and result instanceof OldIR::CallTargetOperand or - newTag instanceof ThisArgumentOperand and result instanceof OldIR::ThisArgumentOperand or - exists(PositionalArgumentOperand newArg | - newArg = newTag and - result.(OldIR::PositionalArgumentOperand).getArgIndex() = newArg.getArgIndex() - ) - } - private IRBlock getNewBlock(OldIR::IRBlock oldBlock) { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } @@ -49,14 +32,6 @@ cached private module Cached { ) } - cached int getMaxCallArgIndex() { - result = max(int argIndex | - exists(OldIR::PositionalArgumentOperand oldOperand | - argIndex = oldOperand.getArgIndex() - ) - ) - } - cached OldIR::Instruction getOldInstruction(Instruction instr) { instr.getTag() = WrappedInstructionTag(result) } @@ -136,17 +111,18 @@ cached private module Cached { } cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) { - exists(OldIR::Instruction oldUse, OldIR::OperandTag oldTag | - oldUse = getOldInstruction(instruction) and - oldTag = getOldOperandTag(tag) and - if oldUse.isMemoryOperand(oldTag) then ( + exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand | + oldInstruction = getOldInstruction(instruction) and + oldOperand = oldInstruction.getAnOperand() and + tag = oldOperand.getOperandTag() and + if oldOperand instanceof OldIR::MemoryOperand then ( ( - if exists(Alias::getOperandMemoryAccess(oldUse, oldTag)) then ( + if exists(Alias::getOperandMemoryAccess(oldOperand)) then ( exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar, OldIR::IRBlock defBlock, int defRank, int defIndex | - vvar = Alias::getOperandMemoryAccess(oldUse, oldTag).getVirtualVariable() and + vvar = Alias::getOperandMemoryAccess(oldOperand).getVirtualVariable() and hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and - hasUseAtRank(vvar, useBlock, useRank, oldUse) and + hasUseAtRank(vvar, useBlock, useRank, oldInstruction) and definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and if defIndex >= 0 then result = getNewInstruction(defBlock.getInstruction(defIndex)) @@ -162,25 +138,24 @@ cached private module Cached { // `UnmodeledUse` instruction. exists(OldIR::Instruction oldDefinition | instruction instanceof UnmodeledUseInstruction and - tag instanceof UnmodeledUseOperand and - oldDefinition = oldUse.getOperand(oldTag) and + tag instanceof UnmodeledUseOperandTag and + oldDefinition = oldOperand.getDefinitionInstruction() and not exists(Alias::getResultMemoryAccess(oldDefinition)) and result = getNewInstruction(oldDefinition) ) ) else - result = getNewInstruction(oldUse.getOperand(oldTag)) - ) or - result = getPhiInstructionOperand(instruction.(PhiInstruction), tag.(PhiOperand)) + result = getNewInstruction(oldOperand.getDefinitionInstruction()) + ) } - cached Instruction getPhiInstructionOperand(PhiInstruction instr, PhiOperand tag) { + cached Instruction getPhiInstructionOperand(PhiInstruction instr, IRBlock newPredecessorBlock) { exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock, OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock | hasPhiNode(vvar, phiBlock) and predBlock = phiBlock.getAPredecessor() and instr.getTag() = PhiTag(vvar, phiBlock) and - tag.getPredecessorBlock() = getNewBlock(predBlock) and + newPredecessorBlock = getNewBlock(predBlock) and hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and if defIndex >= 0 then @@ -277,7 +252,7 @@ cached private module Cached { private predicate hasUse(Alias::VirtualVariable vvar, OldIR::Instruction use, OldIR::IRBlock block, int index) { exists(Alias::MemoryAccess access | - access = Alias::getOperandMemoryAccess(use, _) and + access = Alias::getOperandMemoryAccess(use.getAnOperand()) and block.getInstruction(index) = use and vvar = access.getVirtualVariable() ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SimpleSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SimpleSSA.qll index a2d8f3532ac7..fdf596267a90 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SimpleSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SimpleSSA.qll @@ -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) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll index 5e84762e7eb8..3fc7e0691258 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll @@ -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 diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 4603cf498481..c95cb23814e6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -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. - */ - final Instruction getOperand(OperandTag tag) { - result = Construction::getInstructionOperand(this, tag) - } - - /** - * Gets all instructions consumed by this instruction's operands. + * Gets all direct uses of the result of this instruction. */ - final Instruction getAnOperand() { - result = getOperand(_) + final Operand getAUse() { + result.getDefinitionInstruction() = this } /** - * Holds if this instruction has a memory operand with the specified tag. + * Gets all of this instruction's operands. */ - final predicate isMemoryOperand(OperandTag tag) { - exists(getOperandMemoryAccess(tag)) + final Operand getAnOperand() { + result.getInstruction() = this } - /** - * 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 } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll new file mode 100644 index 000000000000..ab0f60fc3183 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -0,0 +1,360 @@ +private import internal.IRInternal +import Instruction +import IRBlock +import cpp +import semmle.code.cpp.ir.implementation.MemoryAccessKind +private import semmle.code.cpp.ir.internal.OperandTag + +private newtype TOperand = + TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) { + defInstr = Construction::getInstructionOperand(instr, tag) + } or + TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) { + defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock) + } + +/** + * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. + */ +class Operand extends TOperand { + string toString() { + result = "Operand" + } + + /** + * Gets the `Instruction` that consumes this operand. + */ + Instruction getInstruction() { + none() + } + + /** + * Gets the `Instruction` whose result is the value of the operand. + */ + Instruction getDefinitionInstruction() { + none() + } + + /** + * Gets a prefix to use when dumping the operand in an operand list. + */ + string getDumpLabel() { + result = "" + } + + /** + * Gets a string describing this operand, suitable for display in IR dumps. This consists of the + * result ID of the instruction consumed by the operand, plus a label identifying the operand + * kind. + * + * For example: `this:r3_5` + */ + final string getDumpString() { + result = getDumpLabel() + getDefinitionInstruction().getResultId() + } + + /** + * Get the order in which the operand should be sorted in the operand list. + */ + int getDumpSortOrder() { + result = -1 + } + + /** + * Gets the kind of memory access performed by the operand. Holds only for memory operands. + */ + MemoryAccessKind getMemoryAccess() { + none() + } + + /** + * Returns the operand that holds the memory address from which the current operand loads its + * value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2` + * is `r1`. + */ + final AddressOperand getAddressOperand() { + getMemoryAccess() instanceof IndirectMemoryAccess and + result.getInstruction() = getInstruction() + } +} + +/** + * An operand that is not an operand of a `PhiInstruction`. + */ +class NonPhiOperand extends Operand, TNonPhiOperand { + Instruction instr; + Instruction defInstr; + OperandTag tag; + + NonPhiOperand() { + this = TNonPhiOperand(instr, tag, defInstr) + } + + override final Instruction getInstruction() { + result = instr + } + + override final Instruction getDefinitionInstruction() { + result = defInstr + } + + override final string getDumpLabel() { + result = tag.getLabel() + } + + override final int getDumpSortOrder() { + result = tag.getSortOrder() + } + + final OperandTag getOperandTag() { + result = tag + } +} + +/** + * The address operand of an instruction that loads or stores a value from + * memory (e.g. `Load`, `Store`). + */ +class AddressOperand extends NonPhiOperand { + AddressOperand() { + this = TNonPhiOperand(_, addressOperand(), _) + } + + override string toString() { + result = "Address" + } +} + +/** + * The source value operand of an instruction that copies this value to its + * result (e.g. `Copy`, `Load`, `Store`). + */ +class CopySourceOperand extends NonPhiOperand { + CopySourceOperand() { + this = TNonPhiOperand(_, copySourceOperand(), _) + } + + override string toString() { + result = "CopySource" + } + + override final MemoryAccessKind getMemoryAccess() { + instr.getOpcode() instanceof Opcode::Load and + result instanceof IndirectMemoryAccess + } +} + +/** + * The sole operand of a unary instruction (e.g. `Convert`, `Negate`). + */ +class UnaryOperand extends NonPhiOperand { + UnaryOperand() { + this = TNonPhiOperand(_, unaryOperand(), _) + } + + override string toString() { + result = "Unary" + } +} + +/** + * The left operand of a binary instruction (e.g. `Add`, `CompareEQ`). + */ +class LeftOperand extends NonPhiOperand { + LeftOperand() { + this = TNonPhiOperand(_, leftOperand(), _) + } + + override string toString() { + result = "Left" + } +} + +/** + * The right operand of a binary instruction (e.g. `Add`, `CompareEQ`). + */ +class RightOperand extends NonPhiOperand { + RightOperand() { + this = TNonPhiOperand(_, rightOperand(), _) + } + + override string toString() { + result = "Right" + } +} + +/** + * The return value operand of a `ReturnValue` instruction. + */ +class ReturnValueOperand extends NonPhiOperand { + ReturnValueOperand() { + this = TNonPhiOperand(_, returnValueOperand(), _) + } + + override string toString() { + result = "ReturnValue" + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof IndirectMemoryAccess + } +} + +/** + * The exception thrown by a `ThrowValue` instruction. + */ +class ExceptionOperand extends NonPhiOperand { + ExceptionOperand() { + this = TNonPhiOperand(_, exceptionOperand(), _) + } + + override string toString() { + result = "Exception" + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof IndirectMemoryAccess + } +} + +/** + * The condition operand of a `ConditionalBranch` or `Switch` instruction. + */ +class ConditionOperand extends NonPhiOperand { + ConditionOperand() { + this = TNonPhiOperand(_, conditionOperand(), _) + } + + override string toString() { + result = "Condition" + } +} + +/** + * An operand of the special `UnmodeledUse` instruction, representing a value + * whose set of uses is unknown. + */ +class UnmodeledUseOperand extends NonPhiOperand { + UnmodeledUseOperand() { + this = TNonPhiOperand(_, unmodeledUseOperand(), _) + } + + override string toString() { + result = "UnmodeledUse" + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof UnmodeledMemoryAccess + } +} + +/** + * The operand representing the target function of an `Call` instruction. + */ +class CallTargetOperand extends NonPhiOperand { + CallTargetOperand() { + this = TNonPhiOperand(_, callTargetOperand(), _) + } + + override string toString() { + result = "CallTarget" + } +} + +/** + * An operand representing an argument to a function call. This includes both + * positional arguments (represented by `PositionalArgumentOperand`) and the + * implicit `this` argument, if any (represented by `ThisArgumentOperand`). + */ +class ArgumentOperand extends NonPhiOperand { + ArgumentOperand() { + exists(ArgumentOperandTag argTag | + this = TNonPhiOperand(_, argTag, _) + ) + } +} + +/** + * An operand representing the implicit 'this' argument to a member function + * call. + */ +class ThisArgumentOperand extends ArgumentOperand { + ThisArgumentOperand() { + this = TNonPhiOperand(_, thisArgumentOperand(), _) + } + + override string toString() { + result = "ThisArgument" + } +} + +/** + * An operand representing an argument to a function call. + */ +class PositionalArgumentOperand extends ArgumentOperand { + int argIndex; + + PositionalArgumentOperand() { + exists(PositionalArgumentOperandTag argTag | + this = TNonPhiOperand(_, argTag, _) and + argIndex = argTag.getArgIndex() + ) + } + + override string toString() { + result = "Arg(" + argIndex + ")" + } +} + +/** + * An operand of a `PhiInstruction`. + */ +class PhiOperand extends Operand, TPhiOperand { + PhiInstruction instr; + Instruction defInstr; + IRBlock predecessorBlock; + + PhiOperand() { + this = TPhiOperand(instr, defInstr, predecessorBlock) + } + + override string toString() { + result = "Phi" + } + + override final PhiInstruction getInstruction() { + result = instr + } + + override final Instruction getDefinitionInstruction() { + result = defInstr + } + + override final int getDumpSortOrder() { + result = 11 + getPredecessorBlock().getDisplayIndex() + } + + override final string getDumpLabel() { + result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" + } + + /** + * Gets the predecessor block from which this value comes. + */ + final IRBlock getPredecessorBlock() { + result = predecessorBlock + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof PhiMemoryAccess + } +} + +/** + * An operand that reads a value from memory. + */ +class MemoryOperand extends Operand { + MemoryOperand() { + exists(getMemoryAccess()) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/OperandTag.qll deleted file mode 100644 index df78fd90cd96..000000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/OperandTag.qll +++ /dev/null @@ -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) -} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index d8c14c0f9508..eb7e3184d510 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -1,6 +1,7 @@ import cpp import semmle.code.cpp.ir.implementation.raw.IR import IRBlockConstruction as BlockConstruction +private import semmle.code.cpp.ir.internal.OperandTag private import semmle.code.cpp.ir.internal.TempVariableTag private import InstructionTag private import TranslatedElement @@ -37,14 +38,6 @@ cached private module Cached { exists(getTranslatedFunction(func)) } - cached int getMaxCallArgIndex() { - result = max(int argIndex | - exists(FunctionCall call | - exists(call.getArgument(argIndex)) - ) - ) - } - cached newtype TInstruction = MkInstruction(FunctionIR funcIR, Opcode opcode, Locatable ast, InstructionTag tag, Type resultType, boolean isGLValue) { @@ -98,6 +91,10 @@ cached private module Cached { instruction.getTag(), tag) } + cached Instruction getPhiInstructionOperand(Instruction instruction, IRBlock predecessorBlock) { + none() + } + cached Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll index 9e30772e5a2c..25959a23473a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll @@ -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() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll index a6b605046330..cbddf84c8904 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll @@ -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()) ) ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 580dbe0f725e..1be620d12062 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -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 diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index 8fc3fd706d07..de70d44d17c7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -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() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll index a6f30acee4fa..be1c3a606d99 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll @@ -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()) ) ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll index 43c5b826e230..49194bd176be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -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() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll index 81d6ac541ab0..6e4bb2c6d1e2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -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() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll index 5e84762e7eb8..3fc7e0691258 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll @@ -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 diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 4603cf498481..c95cb23814e6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -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. - */ - final Instruction getOperand(OperandTag tag) { - result = Construction::getInstructionOperand(this, tag) - } - - /** - * Gets all instructions consumed by this instruction's operands. + * Gets all direct uses of the result of this instruction. */ - final Instruction getAnOperand() { - result = getOperand(_) + final Operand getAUse() { + result.getDefinitionInstruction() = this } /** - * Holds if this instruction has a memory operand with the specified tag. + * Gets all of this instruction's operands. */ - final predicate isMemoryOperand(OperandTag tag) { - exists(getOperandMemoryAccess(tag)) + final Operand getAnOperand() { + result.getInstruction() = this } - /** - * 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 } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll new file mode 100644 index 000000000000..ab0f60fc3183 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -0,0 +1,360 @@ +private import internal.IRInternal +import Instruction +import IRBlock +import cpp +import semmle.code.cpp.ir.implementation.MemoryAccessKind +private import semmle.code.cpp.ir.internal.OperandTag + +private newtype TOperand = + TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) { + defInstr = Construction::getInstructionOperand(instr, tag) + } or + TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) { + defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock) + } + +/** + * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. + */ +class Operand extends TOperand { + string toString() { + result = "Operand" + } + + /** + * Gets the `Instruction` that consumes this operand. + */ + Instruction getInstruction() { + none() + } + + /** + * Gets the `Instruction` whose result is the value of the operand. + */ + Instruction getDefinitionInstruction() { + none() + } + + /** + * Gets a prefix to use when dumping the operand in an operand list. + */ + string getDumpLabel() { + result = "" + } + + /** + * Gets a string describing this operand, suitable for display in IR dumps. This consists of the + * result ID of the instruction consumed by the operand, plus a label identifying the operand + * kind. + * + * For example: `this:r3_5` + */ + final string getDumpString() { + result = getDumpLabel() + getDefinitionInstruction().getResultId() + } + + /** + * Get the order in which the operand should be sorted in the operand list. + */ + int getDumpSortOrder() { + result = -1 + } + + /** + * Gets the kind of memory access performed by the operand. Holds only for memory operands. + */ + MemoryAccessKind getMemoryAccess() { + none() + } + + /** + * Returns the operand that holds the memory address from which the current operand loads its + * value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2` + * is `r1`. + */ + final AddressOperand getAddressOperand() { + getMemoryAccess() instanceof IndirectMemoryAccess and + result.getInstruction() = getInstruction() + } +} + +/** + * An operand that is not an operand of a `PhiInstruction`. + */ +class NonPhiOperand extends Operand, TNonPhiOperand { + Instruction instr; + Instruction defInstr; + OperandTag tag; + + NonPhiOperand() { + this = TNonPhiOperand(instr, tag, defInstr) + } + + override final Instruction getInstruction() { + result = instr + } + + override final Instruction getDefinitionInstruction() { + result = defInstr + } + + override final string getDumpLabel() { + result = tag.getLabel() + } + + override final int getDumpSortOrder() { + result = tag.getSortOrder() + } + + final OperandTag getOperandTag() { + result = tag + } +} + +/** + * The address operand of an instruction that loads or stores a value from + * memory (e.g. `Load`, `Store`). + */ +class AddressOperand extends NonPhiOperand { + AddressOperand() { + this = TNonPhiOperand(_, addressOperand(), _) + } + + override string toString() { + result = "Address" + } +} + +/** + * The source value operand of an instruction that copies this value to its + * result (e.g. `Copy`, `Load`, `Store`). + */ +class CopySourceOperand extends NonPhiOperand { + CopySourceOperand() { + this = TNonPhiOperand(_, copySourceOperand(), _) + } + + override string toString() { + result = "CopySource" + } + + override final MemoryAccessKind getMemoryAccess() { + instr.getOpcode() instanceof Opcode::Load and + result instanceof IndirectMemoryAccess + } +} + +/** + * The sole operand of a unary instruction (e.g. `Convert`, `Negate`). + */ +class UnaryOperand extends NonPhiOperand { + UnaryOperand() { + this = TNonPhiOperand(_, unaryOperand(), _) + } + + override string toString() { + result = "Unary" + } +} + +/** + * The left operand of a binary instruction (e.g. `Add`, `CompareEQ`). + */ +class LeftOperand extends NonPhiOperand { + LeftOperand() { + this = TNonPhiOperand(_, leftOperand(), _) + } + + override string toString() { + result = "Left" + } +} + +/** + * The right operand of a binary instruction (e.g. `Add`, `CompareEQ`). + */ +class RightOperand extends NonPhiOperand { + RightOperand() { + this = TNonPhiOperand(_, rightOperand(), _) + } + + override string toString() { + result = "Right" + } +} + +/** + * The return value operand of a `ReturnValue` instruction. + */ +class ReturnValueOperand extends NonPhiOperand { + ReturnValueOperand() { + this = TNonPhiOperand(_, returnValueOperand(), _) + } + + override string toString() { + result = "ReturnValue" + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof IndirectMemoryAccess + } +} + +/** + * The exception thrown by a `ThrowValue` instruction. + */ +class ExceptionOperand extends NonPhiOperand { + ExceptionOperand() { + this = TNonPhiOperand(_, exceptionOperand(), _) + } + + override string toString() { + result = "Exception" + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof IndirectMemoryAccess + } +} + +/** + * The condition operand of a `ConditionalBranch` or `Switch` instruction. + */ +class ConditionOperand extends NonPhiOperand { + ConditionOperand() { + this = TNonPhiOperand(_, conditionOperand(), _) + } + + override string toString() { + result = "Condition" + } +} + +/** + * An operand of the special `UnmodeledUse` instruction, representing a value + * whose set of uses is unknown. + */ +class UnmodeledUseOperand extends NonPhiOperand { + UnmodeledUseOperand() { + this = TNonPhiOperand(_, unmodeledUseOperand(), _) + } + + override string toString() { + result = "UnmodeledUse" + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof UnmodeledMemoryAccess + } +} + +/** + * The operand representing the target function of an `Call` instruction. + */ +class CallTargetOperand extends NonPhiOperand { + CallTargetOperand() { + this = TNonPhiOperand(_, callTargetOperand(), _) + } + + override string toString() { + result = "CallTarget" + } +} + +/** + * An operand representing an argument to a function call. This includes both + * positional arguments (represented by `PositionalArgumentOperand`) and the + * implicit `this` argument, if any (represented by `ThisArgumentOperand`). + */ +class ArgumentOperand extends NonPhiOperand { + ArgumentOperand() { + exists(ArgumentOperandTag argTag | + this = TNonPhiOperand(_, argTag, _) + ) + } +} + +/** + * An operand representing the implicit 'this' argument to a member function + * call. + */ +class ThisArgumentOperand extends ArgumentOperand { + ThisArgumentOperand() { + this = TNonPhiOperand(_, thisArgumentOperand(), _) + } + + override string toString() { + result = "ThisArgument" + } +} + +/** + * An operand representing an argument to a function call. + */ +class PositionalArgumentOperand extends ArgumentOperand { + int argIndex; + + PositionalArgumentOperand() { + exists(PositionalArgumentOperandTag argTag | + this = TNonPhiOperand(_, argTag, _) and + argIndex = argTag.getArgIndex() + ) + } + + override string toString() { + result = "Arg(" + argIndex + ")" + } +} + +/** + * An operand of a `PhiInstruction`. + */ +class PhiOperand extends Operand, TPhiOperand { + PhiInstruction instr; + Instruction defInstr; + IRBlock predecessorBlock; + + PhiOperand() { + this = TPhiOperand(instr, defInstr, predecessorBlock) + } + + override string toString() { + result = "Phi" + } + + override final PhiInstruction getInstruction() { + result = instr + } + + override final Instruction getDefinitionInstruction() { + result = defInstr + } + + override final int getDumpSortOrder() { + result = 11 + getPredecessorBlock().getDisplayIndex() + } + + override final string getDumpLabel() { + result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":" + } + + /** + * Gets the predecessor block from which this value comes. + */ + final IRBlock getPredecessorBlock() { + result = predecessorBlock + } + + override final MemoryAccessKind getMemoryAccess() { + result instanceof PhiMemoryAccess + } +} + +/** + * An operand that reads a value from memory. + */ +class MemoryOperand extends Operand { + MemoryOperand() { + exists(getMemoryAccess()) + } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/OperandTag.qll deleted file mode 100644 index df78fd90cd96..000000000000 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/OperandTag.qll +++ /dev/null @@ -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) -} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index f3be51b63d2d..fb897afa58d6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -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) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 70af6ce64138..ebd9952d7d2b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -1,30 +1,13 @@ import SSAConstructionInternal import cpp private import semmle.code.cpp.ir.implementation.Opcode -import NewIR +private import semmle.code.cpp.ir.internal.OperandTag +private import NewIR import IRBlockConstruction as BlockConstruction import Cached cached private module Cached { - private OldIR::OperandTag getOldOperandTag(OperandTag newTag) { - newTag instanceof LoadStoreAddressOperand and result instanceof OldIR::LoadStoreAddressOperand or - newTag instanceof CopySourceOperand and result instanceof OldIR::CopySourceOperand or - newTag instanceof UnaryOperand and result instanceof OldIR::UnaryOperand or - newTag instanceof LeftOperand and result instanceof OldIR::LeftOperand or - newTag instanceof RightOperand and result instanceof OldIR::RightOperand or - newTag instanceof ReturnValueOperand and result instanceof OldIR::ReturnValueOperand or - newTag instanceof ExceptionOperand and result instanceof OldIR::ExceptionOperand or - newTag instanceof ConditionOperand and result instanceof OldIR::ConditionOperand or - newTag instanceof UnmodeledUseOperand and result instanceof OldIR::UnmodeledUseOperand or - newTag instanceof CallTargetOperand and result instanceof OldIR::CallTargetOperand or - newTag instanceof ThisArgumentOperand and result instanceof OldIR::ThisArgumentOperand or - exists(PositionalArgumentOperand newArg | - newArg = newTag and - result.(OldIR::PositionalArgumentOperand).getArgIndex() = newArg.getArgIndex() - ) - } - private IRBlock getNewBlock(OldIR::IRBlock oldBlock) { result.getFirstInstruction() = getNewInstruction(oldBlock.getFirstInstruction()) } @@ -49,14 +32,6 @@ cached private module Cached { ) } - cached int getMaxCallArgIndex() { - result = max(int argIndex | - exists(OldIR::PositionalArgumentOperand oldOperand | - argIndex = oldOperand.getArgIndex() - ) - ) - } - cached OldIR::Instruction getOldInstruction(Instruction instr) { instr.getTag() = WrappedInstructionTag(result) } @@ -136,17 +111,18 @@ cached private module Cached { } cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) { - exists(OldIR::Instruction oldUse, OldIR::OperandTag oldTag | - oldUse = getOldInstruction(instruction) and - oldTag = getOldOperandTag(tag) and - if oldUse.isMemoryOperand(oldTag) then ( + exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand | + oldInstruction = getOldInstruction(instruction) and + oldOperand = oldInstruction.getAnOperand() and + tag = oldOperand.getOperandTag() and + if oldOperand instanceof OldIR::MemoryOperand then ( ( - if exists(Alias::getOperandMemoryAccess(oldUse, oldTag)) then ( + if exists(Alias::getOperandMemoryAccess(oldOperand)) then ( exists(OldIR::IRBlock useBlock, int useRank, Alias::VirtualVariable vvar, OldIR::IRBlock defBlock, int defRank, int defIndex | - vvar = Alias::getOperandMemoryAccess(oldUse, oldTag).getVirtualVariable() and + vvar = Alias::getOperandMemoryAccess(oldOperand).getVirtualVariable() and hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and - hasUseAtRank(vvar, useBlock, useRank, oldUse) and + hasUseAtRank(vvar, useBlock, useRank, oldInstruction) and definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and if defIndex >= 0 then result = getNewInstruction(defBlock.getInstruction(defIndex)) @@ -162,25 +138,24 @@ cached private module Cached { // `UnmodeledUse` instruction. exists(OldIR::Instruction oldDefinition | instruction instanceof UnmodeledUseInstruction and - tag instanceof UnmodeledUseOperand and - oldDefinition = oldUse.getOperand(oldTag) and + tag instanceof UnmodeledUseOperandTag and + oldDefinition = oldOperand.getDefinitionInstruction() and not exists(Alias::getResultMemoryAccess(oldDefinition)) and result = getNewInstruction(oldDefinition) ) ) else - result = getNewInstruction(oldUse.getOperand(oldTag)) - ) or - result = getPhiInstructionOperand(instruction.(PhiInstruction), tag.(PhiOperand)) + result = getNewInstruction(oldOperand.getDefinitionInstruction()) + ) } - cached Instruction getPhiInstructionOperand(PhiInstruction instr, PhiOperand tag) { + cached Instruction getPhiInstructionOperand(PhiInstruction instr, IRBlock newPredecessorBlock) { exists(Alias::VirtualVariable vvar, OldIR::IRBlock phiBlock, OldIR::IRBlock defBlock, int defRank, int defIndex, OldIR::IRBlock predBlock | hasPhiNode(vvar, phiBlock) and predBlock = phiBlock.getAPredecessor() and instr.getTag() = PhiTag(vvar, phiBlock) and - tag.getPredecessorBlock() = getNewBlock(predBlock) and + newPredecessorBlock = getNewBlock(predBlock) and hasDefinitionAtRank(vvar, defBlock, defRank, defIndex) and definitionReachesEndOfBlock(vvar, defBlock, defRank, predBlock) and if defIndex >= 0 then @@ -277,7 +252,7 @@ cached private module Cached { private predicate hasUse(Alias::VirtualVariable vvar, OldIR::Instruction use, OldIR::IRBlock block, int index) { exists(Alias::MemoryAccess access | - access = Alias::getOperandMemoryAccess(use, _) and + access = Alias::getOperandMemoryAccess(use.getAnOperand()) and block.getInstruction(index) = use and vvar = access.getVirtualVariable() ) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll index a2d8f3532ac7..fdf596267a90 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll @@ -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) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/OperandTag.qll b/cpp/ql/src/semmle/code/cpp/ir/internal/OperandTag.qll similarity index 64% rename from cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/OperandTag.qll rename to cpp/ql/src/semmle/code/cpp/ir/internal/OperandTag.qll index df78fd90cd96..a8063aaaf9de 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/OperandTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/internal/OperandTag.qll @@ -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) -} diff --git a/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql b/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql index 1cd4a523a3c1..54d29000fdd2 100644 --- a/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql +++ b/cpp/ql/test/library-tests/ir/constant_func/constant_func.ql @@ -19,8 +19,8 @@ IntValue getConstantValue(Instruction instr) { result = getConstantValue(instr.(CopyInstruction).getSourceValue()) or exists(PhiInstruction phi | phi = instr and - result = max(Instruction operand | operand = phi.getAnOperand() | getConstantValue(operand)) and - result = min(Instruction operand | operand = phi.getAnOperand() | getConstantValue(operand)) + result = max(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) and + result = min(PhiOperand operand | operand = phi.getAnOperand() | getConstantValue(operand.getDefinitionInstruction())) ) } From 459b05d875a3ba86f32adb37000c831cfab7f773 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 26 Oct 2018 14:38:34 -0700 Subject: [PATCH 2/2] C++: Rename a couple predicates based on PR feedback --- .../code/cpp/ir/implementation/aliased_ssa/Operand.qll | 4 ++-- .../implementation/aliased_ssa/internal/SSAConstruction.qll | 5 +++-- cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll | 4 ++-- .../cpp/ir/implementation/raw/internal/IRConstruction.qll | 5 +++-- .../code/cpp/ir/implementation/unaliased_ssa/Operand.qll | 4 ++-- .../unaliased_ssa/internal/SSAConstruction.qll | 5 +++-- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index ab0f60fc3183..4cc82d0906ca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -7,10 +7,10 @@ private import semmle.code.cpp.ir.internal.OperandTag private newtype TOperand = TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) { - defInstr = Construction::getInstructionOperand(instr, tag) + defInstr = Construction::getInstructionOperandDefinition(instr, tag) } or TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) { - defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock) + defInstr = Construction::getPhiInstructionOperandDefinition(instr, predecessorBlock) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index ebd9952d7d2b..5dbf34cb6c32 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -110,7 +110,7 @@ cached private module Cached { instruction instanceof PhiInstruction // Phis always have modeled results } - cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) { + cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) { exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand | oldInstruction = getOldInstruction(instruction) and oldOperand = oldInstruction.getAnOperand() and @@ -149,7 +149,8 @@ cached private module Cached { ) } - cached Instruction getPhiInstructionOperand(PhiInstruction instr, IRBlock newPredecessorBlock) { + 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 diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index ab0f60fc3183..4cc82d0906ca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -7,10 +7,10 @@ private import semmle.code.cpp.ir.internal.OperandTag private newtype TOperand = TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) { - defInstr = Construction::getInstructionOperand(instr, tag) + defInstr = Construction::getInstructionOperandDefinition(instr, tag) } or TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) { - defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock) + defInstr = Construction::getPhiInstructionOperandDefinition(instr, predecessorBlock) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll index eb7e3184d510..9fdece58e41e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll @@ -86,12 +86,13 @@ 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 getPhiInstructionOperand(Instruction instruction, IRBlock predecessorBlock) { + cached Instruction getPhiInstructionOperandDefinition(Instruction instruction, + IRBlock predecessorBlock) { none() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index ab0f60fc3183..4cc82d0906ca 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -7,10 +7,10 @@ private import semmle.code.cpp.ir.internal.OperandTag private newtype TOperand = TNonPhiOperand(Instruction instr, OperandTag tag, Instruction defInstr) { - defInstr = Construction::getInstructionOperand(instr, tag) + defInstr = Construction::getInstructionOperandDefinition(instr, tag) } or TPhiOperand(PhiInstruction instr, Instruction defInstr, IRBlock predecessorBlock) { - defInstr = Construction::getPhiInstructionOperand(instr, predecessorBlock) + defInstr = Construction::getPhiInstructionOperandDefinition(instr, predecessorBlock) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index ebd9952d7d2b..5dbf34cb6c32 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -110,7 +110,7 @@ cached private module Cached { instruction instanceof PhiInstruction // Phis always have modeled results } - cached Instruction getInstructionOperand(Instruction instruction, OperandTag tag) { + cached Instruction getInstructionOperandDefinition(Instruction instruction, OperandTag tag) { exists(OldIR::Instruction oldInstruction, OldIR::NonPhiOperand oldOperand | oldInstruction = getOldInstruction(instruction) and oldOperand = oldInstruction.getAnOperand() and @@ -149,7 +149,8 @@ cached private module Cached { ) } - cached Instruction getPhiInstructionOperand(PhiInstruction instr, IRBlock newPredecessorBlock) { + 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