mirror of
https://github.com/github/codeql.git
synced 2026-04-26 01:05:15 +02:00
C++: Add conservative side effects for function calls
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import cpp
|
||||
|
||||
newtype TMemoryAccessKind =
|
||||
private newtype TMemoryAccessKind =
|
||||
TIndirectMemoryAccess() or
|
||||
TIndirectMayMemoryAccess() or
|
||||
TBufferMemoryAccess() or
|
||||
TBufferMayMemoryAccess() or
|
||||
TEscapedMemoryAccess() or
|
||||
TPhiMemoryAccess() or
|
||||
TUnmodeledMemoryAccess()
|
||||
@@ -15,8 +18,8 @@ class MemoryAccessKind extends TMemoryAccessKind {
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result accesses memory at the address specified by the
|
||||
* `AddressOperand` on the same instruction.
|
||||
* The operand or result accesses memory at the address specified by the `AddressOperand` on the
|
||||
* same instruction.
|
||||
*/
|
||||
class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
|
||||
override string toString() {
|
||||
@@ -24,6 +27,38 @@ class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result may access some, all, or none of the memory at the address specified by the
|
||||
* `AddressOperand` on the same instruction.
|
||||
*/
|
||||
class IndirectMayMemoryAccess extends MemoryAccessKind, TIndirectMayMemoryAccess {
|
||||
override string toString() {
|
||||
result = "indirect(may)"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result accesses memory starting at the address specified by the `AddressOperand`
|
||||
* on the same instruction, accessing a number of consecutive elements given by the
|
||||
* `BufferSizeOperand`.
|
||||
*/
|
||||
class BufferMemoryAccess extends MemoryAccessKind, TBufferMemoryAccess {
|
||||
override string toString() {
|
||||
result = "buffer"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result may access some, all, or none of the memory starting at the address
|
||||
* specified by the `AddressOperand` on the same instruction, accessing a number of consecutive
|
||||
* elements given by the `BufferSizeOperand`.
|
||||
*/
|
||||
class BufferMayMemoryAccess extends MemoryAccessKind, TBufferMayMemoryAccess {
|
||||
override string toString() {
|
||||
result = "buffer(may)"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand or result accesses all memory whose address has escaped.
|
||||
*/
|
||||
|
||||
@@ -58,7 +58,15 @@ private newtype TOpcode =
|
||||
TVarArgsStart() or
|
||||
TVarArgsEnd() or
|
||||
TVarArg() or
|
||||
TVarArgCopy()
|
||||
TVarArgCopy() or
|
||||
TCallSideEffect() or
|
||||
TCallReadSideEffect() or
|
||||
TIndirectReadSideEffect() or
|
||||
TIndirectWriteSideEffect() or
|
||||
TIndirectMayWriteSideEffect() or
|
||||
TBufferReadSideEffect() or
|
||||
TBufferWriteSideEffect() or
|
||||
TBufferMayWriteSideEffect()
|
||||
|
||||
class Opcode extends TOpcode {
|
||||
string toString() {
|
||||
@@ -92,6 +100,29 @@ abstract class OpcodeWithCondition extends Opcode {}
|
||||
|
||||
abstract class BuiltInOpcode extends Opcode {}
|
||||
|
||||
abstract class SideEffectOpcode extends Opcode {}
|
||||
|
||||
/**
|
||||
* An opcode that reads from a set of memory locations as a side effect.
|
||||
*/
|
||||
abstract class ReadSideEffectOpcode extends SideEffectOpcode {}
|
||||
|
||||
/**
|
||||
* An opcode that writes to a set of memory locations as a side effect.
|
||||
*/
|
||||
abstract class WriteSideEffectOpcode extends SideEffectOpcode {}
|
||||
|
||||
/**
|
||||
* An opcode that may overwrite some, all, or none of an existing set of memory locations. Modeled
|
||||
* as a read of the original contents, plus a "may" write of the new contents.
|
||||
*/
|
||||
abstract class MayWriteSideEffectOpcode extends SideEffectOpcode {}
|
||||
|
||||
/**
|
||||
* An opcode that accesses a buffer via an `AddressOperand` and a `BufferSizeOperand`.
|
||||
*/
|
||||
abstract class BufferAccessOpcode extends MemoryAccessOpcode {}
|
||||
|
||||
module Opcode {
|
||||
class NoOp extends Opcode, TNoOp { override final string toString() { result = "NoOp" } }
|
||||
class Uninitialized extends MemoryAccessOpcode, TUninitialized { override final string toString() { result = "Uninitialized" } }
|
||||
@@ -153,4 +184,12 @@ module Opcode {
|
||||
class VarArgsEnd extends BuiltInOpcode, TVarArgsEnd { override final string toString() { result = "VarArgsEnd" } }
|
||||
class VarArg extends BuiltInOpcode, TVarArg { override final string toString() { result = "VarArg" } }
|
||||
class VarArgCopy extends BuiltInOpcode, TVarArgCopy { override final string toString() { result = "VarArgCopy" } }
|
||||
class CallSideEffect extends MayWriteSideEffectOpcode, TCallSideEffect { override final string toString() { result = "CallSideEffect" } }
|
||||
class CallReadSideEffect extends ReadSideEffectOpcode, TCallReadSideEffect { override final string toString() { result = "CallReadSideEffect" } }
|
||||
class IndirectReadSideEffect extends ReadSideEffectOpcode, MemoryAccessOpcode, TIndirectReadSideEffect { override final string toString() { result = "IndirectReadSideEffect" } }
|
||||
class IndirectWriteSideEffect extends WriteSideEffectOpcode, MemoryAccessOpcode, TIndirectWriteSideEffect { override final string toString() { result = "IndirectWriteSideEffect" } }
|
||||
class IndirectMayWriteSideEffect extends MayWriteSideEffectOpcode, MemoryAccessOpcode, TIndirectMayWriteSideEffect { override final string toString() { result = "IndirectMayWriteSideEffect" } }
|
||||
class BufferReadSideEffect extends ReadSideEffectOpcode, BufferAccessOpcode, TBufferReadSideEffect { override final string toString() { result = "BufferReadSideEffect" } }
|
||||
class BufferWriteSideEffect extends WriteSideEffectOpcode, BufferAccessOpcode, TBufferWriteSideEffect { override final string toString() { result = "BufferWriteSideEffect" } }
|
||||
class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode, TBufferMayWriteSideEffect { override final string toString() { result = "BufferMayWriteSideEffect" } }
|
||||
}
|
||||
|
||||
@@ -33,11 +33,16 @@ module InstructionSanity {
|
||||
) or
|
||||
opcode instanceof CopyOpcode and tag instanceof CopySourceOperandTag or
|
||||
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or
|
||||
opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand 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
|
||||
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or
|
||||
(
|
||||
(opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode) and
|
||||
tag instanceof SideEffectOperandTag
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -162,9 +167,9 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
final string getOperationString() {
|
||||
if exists(getImmediateString()) then
|
||||
result = opcode.toString() + "[" + getImmediateString() + "]"
|
||||
result = getOperationPrefix() + opcode.toString() + "[" + getImmediateString() + "]"
|
||||
else
|
||||
result = opcode.toString()
|
||||
result = getOperationPrefix() + opcode.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,6 +179,13 @@ class Instruction extends Construction::TInstruction {
|
||||
none()
|
||||
}
|
||||
|
||||
private string getOperationPrefix() {
|
||||
if this instanceof SideEffectInstruction then
|
||||
result = "^"
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if resultType instanceof VoidType then
|
||||
result = "v"
|
||||
@@ -1084,6 +1096,9 @@ class SwitchInstruction extends Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that calls a function.
|
||||
*/
|
||||
class CallInstruction extends Instruction {
|
||||
CallInstruction() {
|
||||
opcode instanceof Opcode::Call
|
||||
@@ -1094,6 +1109,116 @@ class CallInstruction extends Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
*/
|
||||
class SideEffectInstruction extends Instruction {
|
||||
SideEffectInstruction() {
|
||||
opcode instanceof SideEffectOpcode
|
||||
}
|
||||
|
||||
final Instruction getPrimaryInstruction() {
|
||||
result = Construction::getPrimaryInstructionForSideEffect(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the side effect of a function call on any memory that might be
|
||||
* accessed by that call.
|
||||
*/
|
||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
CallSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof EscapedMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the side effect of a function call on any memory that might be read
|
||||
* by that call.
|
||||
*/
|
||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
CallReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect parameter within a function call.
|
||||
*/
|
||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect buffer parameter within a function call.
|
||||
*/
|
||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the write of an indirect parameter within a function call.
|
||||
*/
|
||||
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the write of an indirect buffer parameter within a function call. The
|
||||
* entire buffer is overwritten.
|
||||
*/
|
||||
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the potential write of an indirect parameter within a function call.
|
||||
* Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten.
|
||||
* written.
|
||||
*/
|
||||
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectMayWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof IndirectMayMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the write of an indirect buffer parameter within a function call.
|
||||
* Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten.
|
||||
*/
|
||||
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferMayWriteSideEffect
|
||||
}
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMayMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that throws an exception.
|
||||
*/
|
||||
|
||||
@@ -306,6 +306,38 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
}
|
||||
}
|
||||
|
||||
class SideEffectOperand extends NonPhiOperand {
|
||||
SideEffectOperand() {
|
||||
this = TNonPhiOperand(_, sideEffectOperand(), _)
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
instr instanceof CallSideEffectInstruction and
|
||||
result instanceof EscapedMemoryAccess
|
||||
or
|
||||
instr instanceof CallReadSideEffectInstruction and
|
||||
result instanceof EscapedMemoryAccess
|
||||
or
|
||||
instr instanceof IndirectReadSideEffectInstruction and
|
||||
result instanceof IndirectMemoryAccess
|
||||
or
|
||||
instr instanceof BufferReadSideEffectInstruction and
|
||||
result instanceof BufferMemoryAccess
|
||||
or
|
||||
instr instanceof IndirectWriteSideEffectInstruction and
|
||||
result instanceof IndirectMemoryAccess
|
||||
or
|
||||
instr instanceof BufferWriteSideEffectInstruction and
|
||||
result instanceof BufferMemoryAccess
|
||||
or
|
||||
instr instanceof IndirectMayWriteSideEffectInstruction and
|
||||
result instanceof IndirectMayMemoryAccess
|
||||
or
|
||||
instr instanceof BufferMayWriteSideEffectInstruction and
|
||||
result instanceof BufferMayMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
@@ -350,6 +382,7 @@ class PhiOperand extends Operand, TPhiOperand {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An operand that reads a value from memory.
|
||||
*/
|
||||
|
||||
@@ -227,6 +227,13 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPrimaryInstructionForSideEffect(Instruction instruction) {
|
||||
exists(OldIR::SideEffectInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
result = getNewInstruction(oldInstruction.getPrimaryInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction instr, OldIR::IRBlock block, int index) {
|
||||
block.getInstruction(index) = instr and
|
||||
|
||||
@@ -33,11 +33,16 @@ module InstructionSanity {
|
||||
) or
|
||||
opcode instanceof CopyOpcode and tag instanceof CopySourceOperandTag or
|
||||
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or
|
||||
opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand 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
|
||||
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or
|
||||
(
|
||||
(opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode) and
|
||||
tag instanceof SideEffectOperandTag
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -162,9 +167,9 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
final string getOperationString() {
|
||||
if exists(getImmediateString()) then
|
||||
result = opcode.toString() + "[" + getImmediateString() + "]"
|
||||
result = getOperationPrefix() + opcode.toString() + "[" + getImmediateString() + "]"
|
||||
else
|
||||
result = opcode.toString()
|
||||
result = getOperationPrefix() + opcode.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,6 +179,13 @@ class Instruction extends Construction::TInstruction {
|
||||
none()
|
||||
}
|
||||
|
||||
private string getOperationPrefix() {
|
||||
if this instanceof SideEffectInstruction then
|
||||
result = "^"
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if resultType instanceof VoidType then
|
||||
result = "v"
|
||||
@@ -1084,6 +1096,9 @@ class SwitchInstruction extends Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that calls a function.
|
||||
*/
|
||||
class CallInstruction extends Instruction {
|
||||
CallInstruction() {
|
||||
opcode instanceof Opcode::Call
|
||||
@@ -1094,6 +1109,116 @@ class CallInstruction extends Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
*/
|
||||
class SideEffectInstruction extends Instruction {
|
||||
SideEffectInstruction() {
|
||||
opcode instanceof SideEffectOpcode
|
||||
}
|
||||
|
||||
final Instruction getPrimaryInstruction() {
|
||||
result = Construction::getPrimaryInstructionForSideEffect(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the side effect of a function call on any memory that might be
|
||||
* accessed by that call.
|
||||
*/
|
||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
CallSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof EscapedMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the side effect of a function call on any memory that might be read
|
||||
* by that call.
|
||||
*/
|
||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
CallReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect parameter within a function call.
|
||||
*/
|
||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect buffer parameter within a function call.
|
||||
*/
|
||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the write of an indirect parameter within a function call.
|
||||
*/
|
||||
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the write of an indirect buffer parameter within a function call. The
|
||||
* entire buffer is overwritten.
|
||||
*/
|
||||
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the potential write of an indirect parameter within a function call.
|
||||
* Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten.
|
||||
* written.
|
||||
*/
|
||||
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectMayWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof IndirectMayMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the write of an indirect buffer parameter within a function call.
|
||||
* Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten.
|
||||
*/
|
||||
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferMayWriteSideEffect
|
||||
}
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMayMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that throws an exception.
|
||||
*/
|
||||
|
||||
@@ -306,6 +306,38 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
}
|
||||
}
|
||||
|
||||
class SideEffectOperand extends NonPhiOperand {
|
||||
SideEffectOperand() {
|
||||
this = TNonPhiOperand(_, sideEffectOperand(), _)
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
instr instanceof CallSideEffectInstruction and
|
||||
result instanceof EscapedMemoryAccess
|
||||
or
|
||||
instr instanceof CallReadSideEffectInstruction and
|
||||
result instanceof EscapedMemoryAccess
|
||||
or
|
||||
instr instanceof IndirectReadSideEffectInstruction and
|
||||
result instanceof IndirectMemoryAccess
|
||||
or
|
||||
instr instanceof BufferReadSideEffectInstruction and
|
||||
result instanceof BufferMemoryAccess
|
||||
or
|
||||
instr instanceof IndirectWriteSideEffectInstruction and
|
||||
result instanceof IndirectMemoryAccess
|
||||
or
|
||||
instr instanceof BufferWriteSideEffectInstruction and
|
||||
result instanceof BufferMemoryAccess
|
||||
or
|
||||
instr instanceof IndirectMayWriteSideEffectInstruction and
|
||||
result instanceof IndirectMayMemoryAccess
|
||||
or
|
||||
instr instanceof BufferMayWriteSideEffectInstruction and
|
||||
result instanceof BufferMayMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
@@ -350,6 +382,7 @@ class PhiOperand extends Operand, TPhiOperand {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An operand that reads a value from memory.
|
||||
*/
|
||||
|
||||
@@ -167,6 +167,13 @@ cached private module Cached {
|
||||
result = element.getInstructionResultSize(tag)
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPrimaryInstructionForSideEffect(Instruction instruction) {
|
||||
exists(TranslatedElement element, InstructionTag tag |
|
||||
instructionOrigin(instruction, element, tag) and
|
||||
result = element.getPrimaryInstructionForSideEffect(tag)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
@@ -43,6 +43,7 @@ newtype TInstructionTag =
|
||||
SwitchBranchTag() or
|
||||
CallTargetTag() or
|
||||
CallTag() or
|
||||
CallSideEffectTag() or
|
||||
AllocationSizeTag() or
|
||||
AllocationElementSizeTag() or
|
||||
AllocationExtentConvertTag() or
|
||||
@@ -113,6 +114,7 @@ string getInstructionTagId(TInstructionTag tag) {
|
||||
tag = SwitchBranchTag() and result = "SwitchBranch" or
|
||||
tag = CallTargetTag() and result = "CallTarget" or
|
||||
tag = CallTag() and result = "Call" or
|
||||
tag = CallSideEffectTag() and result = "CallSideEffect" or
|
||||
tag = AllocationSizeTag() and result = "AllocSize" or
|
||||
tag = AllocationElementSizeTag() and result = "AllocElemSize" or
|
||||
tag = AllocationExtentConvertTag() and result = "AllocExtConv" or
|
||||
|
||||
@@ -534,6 +534,14 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
result = getParent().getExceptionSuccessorInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the primary instruction for the side effect instruction that was
|
||||
* generated by this element for tag `tag`.
|
||||
*/
|
||||
Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element generates a temporary variable with type `type`.
|
||||
* `tag` must be unique for each variable generated from the same AST node
|
||||
|
||||
@@ -33,11 +33,16 @@ module InstructionSanity {
|
||||
) or
|
||||
opcode instanceof CopyOpcode and tag instanceof CopySourceOperandTag or
|
||||
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag or
|
||||
opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand 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
|
||||
opcode instanceof Opcode::Call and tag instanceof CallTargetOperandTag or
|
||||
(
|
||||
(opcode instanceof ReadSideEffectOpcode or opcode instanceof MayWriteSideEffectOpcode) and
|
||||
tag instanceof SideEffectOperandTag
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -162,9 +167,9 @@ class Instruction extends Construction::TInstruction {
|
||||
*/
|
||||
final string getOperationString() {
|
||||
if exists(getImmediateString()) then
|
||||
result = opcode.toString() + "[" + getImmediateString() + "]"
|
||||
result = getOperationPrefix() + opcode.toString() + "[" + getImmediateString() + "]"
|
||||
else
|
||||
result = opcode.toString()
|
||||
result = getOperationPrefix() + opcode.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,6 +179,13 @@ class Instruction extends Construction::TInstruction {
|
||||
none()
|
||||
}
|
||||
|
||||
private string getOperationPrefix() {
|
||||
if this instanceof SideEffectInstruction then
|
||||
result = "^"
|
||||
else
|
||||
result = ""
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if resultType instanceof VoidType then
|
||||
result = "v"
|
||||
@@ -1084,6 +1096,9 @@ class SwitchInstruction extends Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that calls a function.
|
||||
*/
|
||||
class CallInstruction extends Instruction {
|
||||
CallInstruction() {
|
||||
opcode instanceof Opcode::Call
|
||||
@@ -1094,6 +1109,116 @@ class CallInstruction extends Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing a side effect of a function call.
|
||||
*/
|
||||
class SideEffectInstruction extends Instruction {
|
||||
SideEffectInstruction() {
|
||||
opcode instanceof SideEffectOpcode
|
||||
}
|
||||
|
||||
final Instruction getPrimaryInstruction() {
|
||||
result = Construction::getPrimaryInstructionForSideEffect(this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the side effect of a function call on any memory that might be
|
||||
* accessed by that call.
|
||||
*/
|
||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||
CallSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof EscapedMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the side effect of a function call on any memory that might be read
|
||||
* by that call.
|
||||
*/
|
||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||
CallReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::CallReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect parameter within a function call.
|
||||
*/
|
||||
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the read of an indirect buffer parameter within a function call.
|
||||
*/
|
||||
class BufferReadSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferReadSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferReadSideEffect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the write of an indirect parameter within a function call.
|
||||
*/
|
||||
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof IndirectMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the write of an indirect buffer parameter within a function call. The
|
||||
* entire buffer is overwritten.
|
||||
*/
|
||||
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the potential write of an indirect parameter within a function call.
|
||||
* Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten.
|
||||
* written.
|
||||
*/
|
||||
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
IndirectMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::IndirectMayWriteSideEffect
|
||||
}
|
||||
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof IndirectMayMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing the write of an indirect buffer parameter within a function call.
|
||||
* Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten.
|
||||
*/
|
||||
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
|
||||
BufferMayWriteSideEffectInstruction() {
|
||||
opcode instanceof Opcode::BufferMayWriteSideEffect
|
||||
}
|
||||
override final MemoryAccessKind getResultMemoryAccess() {
|
||||
result instanceof BufferMayMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that throws an exception.
|
||||
*/
|
||||
|
||||
@@ -306,6 +306,38 @@ class PositionalArgumentOperand extends ArgumentOperand {
|
||||
}
|
||||
}
|
||||
|
||||
class SideEffectOperand extends NonPhiOperand {
|
||||
SideEffectOperand() {
|
||||
this = TNonPhiOperand(_, sideEffectOperand(), _)
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
instr instanceof CallSideEffectInstruction and
|
||||
result instanceof EscapedMemoryAccess
|
||||
or
|
||||
instr instanceof CallReadSideEffectInstruction and
|
||||
result instanceof EscapedMemoryAccess
|
||||
or
|
||||
instr instanceof IndirectReadSideEffectInstruction and
|
||||
result instanceof IndirectMemoryAccess
|
||||
or
|
||||
instr instanceof BufferReadSideEffectInstruction and
|
||||
result instanceof BufferMemoryAccess
|
||||
or
|
||||
instr instanceof IndirectWriteSideEffectInstruction and
|
||||
result instanceof IndirectMemoryAccess
|
||||
or
|
||||
instr instanceof BufferWriteSideEffectInstruction and
|
||||
result instanceof BufferMemoryAccess
|
||||
or
|
||||
instr instanceof IndirectMayWriteSideEffectInstruction and
|
||||
result instanceof IndirectMayMemoryAccess
|
||||
or
|
||||
instr instanceof BufferMayWriteSideEffectInstruction and
|
||||
result instanceof BufferMayMemoryAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
@@ -350,6 +382,7 @@ class PhiOperand extends Operand, TPhiOperand {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An operand that reads a value from memory.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import SSAConstructionInternal
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.ir.internal.OperandTag
|
||||
private import NewIR
|
||||
|
||||
import Cached
|
||||
@@ -226,6 +227,13 @@ cached private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached Instruction getPrimaryInstructionForSideEffect(Instruction instruction) {
|
||||
exists(OldIR::SideEffectInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
result = getNewInstruction(oldInstruction.getPrimaryInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
private predicate ssa_variableUpdate(Alias::VirtualVariable vvar,
|
||||
OldIR::Instruction instr, OldIR::IRBlock block, int index) {
|
||||
block.getInstruction(index) = instr and
|
||||
|
||||
@@ -10,6 +10,8 @@ private int getMaxCallArgIndex() {
|
||||
|
||||
private newtype TOperandTag =
|
||||
TAddressOperand() or
|
||||
TBufferSizeOperand() or
|
||||
TSideEffectOperand() or
|
||||
TCopySourceOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
@@ -25,7 +27,7 @@ private newtype TOperandTag =
|
||||
exists(BuiltInOperation op |
|
||||
exists(op.getChild(argIndex))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
@@ -47,7 +49,7 @@ abstract class OperandTag extends TOperandTag {
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`).
|
||||
* memory (e.g. `Load`, `Store`, `InitializeParameter`, `IndirectReadSideEffect`).
|
||||
*/
|
||||
class AddressOperandTag extends OperandTag, TAddressOperand {
|
||||
override final string toString() {
|
||||
@@ -63,6 +65,37 @@ AddressOperandTag addressOperand() {
|
||||
result = TAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The buffer size operand of an instruction that represents a read or write of
|
||||
* a buffer.
|
||||
*/
|
||||
class BufferSizeOperand extends OperandTag, TBufferSizeOperand {
|
||||
override final string toString() {
|
||||
result = "BufferSize"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the read side effect of a `SideEffectInstruction`.
|
||||
*/
|
||||
class SideEffectOperandTag extends OperandTag, TSideEffectOperand {
|
||||
override final string toString() {
|
||||
result = "SideEffect"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
SideEffectOperandTag sideEffectOperand() {
|
||||
result = TSideEffectOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that copies this value to its
|
||||
* result (e.g. `Copy`, `Load`, `Store`).
|
||||
@@ -73,7 +106,7 @@ class CopySourceOperandTag extends OperandTag, TCopySourceOperand {
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
result = 3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +123,7 @@ class UnaryOperandTag extends OperandTag, TUnaryOperand {
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
result = 4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +140,7 @@ class LeftOperandTag extends OperandTag, TLeftOperand {
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
result = 5
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +157,7 @@ class RightOperandTag extends OperandTag, TRightOperand {
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
result = 6
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +174,7 @@ class ReturnValueOperandTag extends OperandTag, TReturnValueOperand {
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
result = 7
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +191,7 @@ class ExceptionOperandTag extends OperandTag, TExceptionOperand {
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
result = 8
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +208,7 @@ class ConditionOperandTag extends OperandTag, TConditionOperand {
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
result = 9
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +226,7 @@ class UnmodeledUseOperandTag extends OperandTag, TUnmodeledUseOperand {
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
result = 10
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +243,7 @@ class CallTargetOperandTag extends OperandTag, TCallTargetOperand {
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
result = 11
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +273,7 @@ class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand {
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
result = 12
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
@@ -268,7 +301,7 @@ class PositionalArgumentOperandTag extends ArgumentOperandTag,
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11 + argIndex
|
||||
result = 14 + argIndex
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
@@ -278,4 +311,4 @@ class PositionalArgumentOperandTag extends ArgumentOperandTag,
|
||||
|
||||
PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user