Merge remote-tracking branch 'upstream/master' into csharp/dataflow/arrays

This commit is contained in:
Tom Hvitved
2020-07-01 14:44:57 +02:00
320 changed files with 17367 additions and 2422 deletions

View File

@@ -3,8 +3,8 @@
"qhelp.dtd">
<qhelp>
<overview>
<p>ECB should not be used as a mode for encryption. It has a dangerous weaknesses. Data is encrypted the same way every time
meaning the same plaintext input will always produce the same cyphertext. This makes encrypted messages very vulnerable
<p>ECB should not be used as a mode for encryption. It has dangerous weaknesses. Data is encrypted the same way every time
meaning the same plaintext input will always produce the same cyphertext. This makes encrypted messages vulnerable
to replay attacks.</p>
</overview>

View File

@@ -1,3 +1,7 @@
/**
* Provides classes that specify the conditions under which control flows along a given edge.
*/
private import internal.EdgeKindInternal
private newtype TEdgeKind =
@@ -77,9 +81,15 @@ class CaseEdge extends EdgeKind, TCaseEdge {
else result = "Case[" + minValue + ".." + maxValue + "]"
}
string getMinValue() { result = minValue }
/**
* Gets the smallest value of the switch expression for which control will flow along this edge.
*/
final string getMinValue() { result = minValue }
string getMaxValue() { result = maxValue }
/**
* Gets the largest value of the switch expression for which control will flow along this edge.
*/
final string getMaxValue() { result = maxValue }
}
/**

View File

@@ -10,6 +10,7 @@ private newtype TIRConfiguration = MkIRConfiguration()
* The query can extend this class to control which functions have IR generated for them.
*/
class IRConfiguration extends TIRConfiguration {
/** Gets a textual representation of this element. */
string toString() { result = "IRConfiguration" }
/**
@@ -17,6 +18,13 @@ class IRConfiguration extends TIRConfiguration {
*/
predicate shouldCreateIRForFunction(Language::Function func) { any() }
/**
* Holds if the strings used as part of an IR dump should be generated for function `func`.
*
* This predicate is overridden in `PrintIR.qll` to avoid the expense of generating a large number
* of debug strings for IR that will not be dumped. We still generate the actual IR for these
* functions, however, to preserve the results of any interprocedural analysis.
*/
predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() }
}
@@ -26,6 +34,7 @@ private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration
* The query can extend this class to control what escape analysis is used when generating SSA.
*/
class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration {
/** Gets a textual representation of this element. */
string toString() { result = "IREscapeAnalysisConfiguration" }
/**

View File

@@ -32,6 +32,7 @@ private newtype TIRType =
* all pointer types map to the same instance of `IRAddressType`.
*/
class IRType extends TIRType {
/** Gets a textual representation of this type. */
string toString() { none() }
/**

View File

@@ -1,3 +1,9 @@
/**
* Provides classes that describe how a particular `Instruction` or its operands access memory.
*/
private import IRConfiguration
private newtype TMemoryAccessKind =
TIndirectMemoryAccess() or
TBufferMemoryAccess() or
@@ -14,6 +20,7 @@ private newtype TMemoryAccessKind =
* memory result.
*/
class MemoryAccessKind extends TMemoryAccessKind {
/** Gets a textual representation of this access kind. */
string toString() { none() }
/**

View File

@@ -1,3 +1,8 @@
/**
* Provides `Opcode`s that specify the operation performed by an `Instruction`, as well as metadata
* about those opcodes, such as operand kinds and memory accesses.
*/
private import internal.OpcodeImports as Imports
private import internal.OperandTag
import Imports::MemoryAccessKind
@@ -45,7 +50,7 @@ private newtype TOpcode =
TConvertToDerived() or
TCheckedConvertOrNull() or
TCheckedConvertOrThrow() or
TDynamicCastToVoid() or
TCompleteObjectAddress() or
TVariableAddress() or
TFieldAddress() or
TFunctionAddress() or
@@ -86,7 +91,11 @@ private newtype TOpcode =
TUnreached() or
TNewObj()
/**
* An opcode that specifies the operation performed by an `Instruction`.
*/
class Opcode extends TOpcode {
/** Gets a textual representation of this element. */
string toString() { result = "UnknownOpcode" }
/**
@@ -139,10 +148,20 @@ class Opcode extends TOpcode {
predicate hasOperandInternal(OperandTag tag) { none() }
}
/**
* The `Opcode` for a `UnaryInstruction`.
*
* See the `UnaryInstruction` documentation for more details.
*/
abstract class UnaryOpcode extends Opcode {
final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag }
}
/**
* The `Opcode` for a `BinaryInstruction`.
*
* See the `BinaryInstruction` documentation for more details.
*/
abstract class BinaryOpcode extends Opcode {
final override predicate hasOperandInternal(OperandTag tag) {
tag instanceof LeftOperandTag or
@@ -150,44 +169,127 @@ abstract class BinaryOpcode extends Opcode {
}
}
/**
* The `Opcode` for a `PointerArithmeticInstruction`.
*
* See the `PointerArithmeticInstruction` documentation for more details.
*/
abstract class PointerArithmeticOpcode extends BinaryOpcode { }
/**
* The `Opcode` for a `PointerOffsetInstruction`.
*
* See the `PointerOffsetInstruction` documentation for more details.
*/
abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { }
/**
* The `Opcode` for an `ArithmeticInstruction`.
*
* See the `ArithmeticInstruction` documentation for more details.
*/
abstract class ArithmeticOpcode extends Opcode { }
/**
* The `Opcode` for a `BinaryArithmeticInstruction`.
*
* See the `BinaryArithmeticInstruction` documentation for more details.
*/
abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { }
/**
* The `Opcode` for a `UnaryArithmeticInstruction`.
*
* See the `UnaryArithmeticInstruction` documentation for more details.
*/
abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { }
/**
* The `Opcode` for a `BitwiseInstruction`.
*
* See the `BitwiseInstruction` documentation for more details.
*/
abstract class BitwiseOpcode extends Opcode { }
/**
* The `Opcode` for a `BinaryBitwiseInstruction`.
*
* See the `BinaryBitwiseInstruction` documentation for more details.
*/
abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { }
/**
* The `Opcode` for a `UnaryBitwiseInstruction`.
*
* See the `UnaryBitwiseInstruction` documentation for more details.
*/
abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { }
/**
* The `Opcode` for a `CompareInstruction`.
*
* See the `CompareInstruction` documentation for more details.
*/
abstract class CompareOpcode extends BinaryOpcode { }
/**
* The `Opcode` for a `RelationalInstruction`.
*
* See the `RelationalInstruction` documentation for more details.
*/
abstract class RelationalOpcode extends CompareOpcode { }
/**
* The `Opcode` for a `CopyInstruction`.
*
* See the `CopyInstruction` documentation for more details.
*/
abstract class CopyOpcode extends Opcode { }
/**
* The `Opcode` for a `ConvertToBaseInstruction`.
*
* See the `ConvertToBaseInstruction` documentation for more details.
*/
abstract class ConvertToBaseOpcode extends UnaryOpcode { }
abstract class MemoryAccessOpcode extends Opcode { }
/**
* The `Opcode` for a `ReturnInstruction`.
*
* See the `ReturnInstruction` documentation for more details.
*/
abstract class ReturnOpcode extends Opcode { }
/**
* The `Opcode` for a `ThrowInstruction`.
*
* See the `ThrowInstruction` documentation for more details.
*/
abstract class ThrowOpcode extends Opcode { }
/**
* The `Opcode` for a `CatchInstruction`.
*
* See the `CatchInstruction` documentation for more details.
*/
abstract class CatchOpcode extends Opcode { }
abstract class OpcodeWithCondition extends Opcode {
abstract private class OpcodeWithCondition extends Opcode {
final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag }
}
/**
* The `Opcode` for a `BuiltInOperationInstruction`.
*
* See the `BuiltInOperationInstruction` documentation for more details.
*/
abstract class BuiltInOperationOpcode extends Opcode { }
/**
* The `Opcode` for a `SideEffectInstruction`.
*
* See the `SideEffectInstruction` documentation for more details.
*/
abstract class SideEffectOpcode extends Opcode { }
/**
@@ -323,7 +425,9 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode {
}
/**
* An opcode that reads from a set of memory locations as a side effect.
* The `Opcode` for a `ReadSideEffectInstruction`.
*
* See the `ReadSideEffectInstruction` documentation for more details.
*/
abstract class ReadSideEffectOpcode extends SideEffectOpcode {
final override predicate hasOperandInternal(OperandTag tag) {
@@ -332,51 +436,111 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode {
}
/**
* An opcode that writes to a set of memory locations as a side effect.
* The `Opcode` for a `WriteSideEffectInstruction`.
*
* See the `WriteSideEffectInstruction` documentation for more details.
*/
abstract class WriteSideEffectOpcode extends SideEffectOpcode { }
/**
* Provides `Opcode`s that specify the operation performed by an `Instruction`.
*/
module Opcode {
/**
* The `Opcode` for a `NoOpInstruction`.
*
* See the `NoOpInstruction` documentation for more details.
*/
class NoOp extends Opcode, TNoOp {
final override string toString() { result = "NoOp" }
}
/**
* The `Opcode` for an `UninitializedInstruction`.
*
* See the `UninitializedInstruction` documentation for more details.
*/
class Uninitialized extends IndirectWriteOpcode, TUninitialized {
final override string toString() { result = "Uninitialized" }
}
/**
* The `Opcode` for an `ErrorInstruction`.
*
* See the `ErrorInstruction` documentation for more details.
*/
class Error extends Opcode, TError {
final override string toString() { result = "Error" }
}
/**
* The `Opcode` for an `InitializeParameterInstruction`.
*
* See the `InitializeParameterInstruction` documentation for more details.
*/
class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter {
final override string toString() { result = "InitializeParameter" }
}
/**
* The `Opcode` for an `InitializeIndirectionInstruction`.
*
* See the `InitializeIndirectionInstruction` documentation for more details.
*/
class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection {
final override string toString() { result = "InitializeIndirection" }
}
/**
* The `Opcode` for an `InitializeThisInstruction`.
*
* See the `InitializeThisInstruction` documentation for more details.
*/
class InitializeThis extends Opcode, TInitializeThis {
final override string toString() { result = "InitializeThis" }
}
/**
* The `Opcode` for an `EnterFunctionInstruction`.
*
* See the `EnterFunctionInstruction` documentation for more details.
*/
class EnterFunction extends Opcode, TEnterFunction {
final override string toString() { result = "EnterFunction" }
}
/**
* The `Opcode` for an `ExitFunctionInstruction`.
*
* See the `ExitFunctionInstruction` documentation for more details.
*/
class ExitFunction extends Opcode, TExitFunction {
final override string toString() { result = "ExitFunction" }
}
/**
* The `Opcode` for a `ReturnValueInstruction`.
*
* See the `ReturnValueInstruction` documentation for more details.
*/
class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue {
final override string toString() { result = "ReturnValue" }
}
/**
* The `Opcode` for a `ReturnVoidInstruction`.
*
* See the `ReturnVoidInstruction` documentation for more details.
*/
class ReturnVoid extends ReturnOpcode, TReturnVoid {
final override string toString() { result = "ReturnVoid" }
}
/**
* The `Opcode` for a `ReturnIndirectionInstruction`.
*
* See the `ReturnIndirectionInstruction` documentation for more details.
*/
class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection {
final override string toString() { result = "ReturnIndirection" }
@@ -385,14 +549,29 @@ module Opcode {
}
}
/**
* The `Opcode` for a `CopyValueInstruction`.
*
* See the `CopyValueInstruction` documentation for more details.
*/
class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue {
final override string toString() { result = "CopyValue" }
}
/**
* The `Opcode` for a `LoadInstruction`.
*
* See the `LoadInstruction` documentation for more details.
*/
class Load extends CopyOpcode, OpcodeWithLoad, TLoad {
final override string toString() { result = "Load" }
}
/**
* The `Opcode` for a `StoreInstruction`.
*
* See the `StoreInstruction` documentation for more details.
*/
class Store extends CopyOpcode, IndirectWriteOpcode, TStore {
final override string toString() { result = "Store" }
@@ -401,154 +580,344 @@ module Opcode {
}
}
/**
* The `Opcode` for an `AddInstruction`.
*
* See the `AddInstruction` documentation for more details.
*/
class Add extends BinaryArithmeticOpcode, TAdd {
final override string toString() { result = "Add" }
}
/**
* The `Opcode` for a `SubInstruction`.
*
* See the `SubInstruction` documentation for more details.
*/
class Sub extends BinaryArithmeticOpcode, TSub {
final override string toString() { result = "Sub" }
}
/**
* The `Opcode` for a `MulInstruction`.
*
* See the `MulInstruction` documentation for more details.
*/
class Mul extends BinaryArithmeticOpcode, TMul {
final override string toString() { result = "Mul" }
}
/**
* The `Opcode` for a `DivInstruction`.
*
* See the `DivInstruction` documentation for more details.
*/
class Div extends BinaryArithmeticOpcode, TDiv {
final override string toString() { result = "Div" }
}
/**
* The `Opcode` for a `RemInstruction`.
*
* See the `RemInstruction` documentation for more details.
*/
class Rem extends BinaryArithmeticOpcode, TRem {
final override string toString() { result = "Rem" }
}
/**
* The `Opcode` for a `NegateInstruction`.
*
* See the `NegateInstruction` documentation for more details.
*/
class Negate extends UnaryArithmeticOpcode, TNegate {
final override string toString() { result = "Negate" }
}
/**
* The `Opcode` for a `ShiftLeftInstruction`.
*
* See the `ShiftLeftInstruction` documentation for more details.
*/
class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft {
final override string toString() { result = "ShiftLeft" }
}
/**
* The `Opcode` for a `ShiftRightInstruction`.
*
* See the `ShiftRightInstruction` documentation for more details.
*/
class ShiftRight extends BinaryBitwiseOpcode, TShiftRight {
final override string toString() { result = "ShiftRight" }
}
/**
* The `Opcode` for a `BitAndInstruction`.
*
* See the `BitAndInstruction` documentation for more details.
*/
class BitAnd extends BinaryBitwiseOpcode, TBitAnd {
final override string toString() { result = "BitAnd" }
}
/**
* The `Opcode` for a `BitOrInstruction`.
*
* See the `BitOrInstruction` documentation for more details.
*/
class BitOr extends BinaryBitwiseOpcode, TBitOr {
final override string toString() { result = "BitOr" }
}
/**
* The `Opcode` for a `BitXorInstruction`.
*
* See the `BitXorInstruction` documentation for more details.
*/
class BitXor extends BinaryBitwiseOpcode, TBitXor {
final override string toString() { result = "BitXor" }
}
/**
* The `Opcode` for a `BitComplementInstruction`.
*
* See the `BitComplementInstruction` documentation for more details.
*/
class BitComplement extends UnaryBitwiseOpcode, TBitComplement {
final override string toString() { result = "BitComplement" }
}
/**
* The `Opcode` for a `LogicalNotInstruction`.
*
* See the `LogicalNotInstruction` documentation for more details.
*/
class LogicalNot extends UnaryOpcode, TLogicalNot {
final override string toString() { result = "LogicalNot" }
}
/**
* The `Opcode` for a `CompareEQInstruction`.
*
* See the `CompareEQInstruction` documentation for more details.
*/
class CompareEQ extends CompareOpcode, TCompareEQ {
final override string toString() { result = "CompareEQ" }
}
/**
* The `Opcode` for a `CompareNEInstruction`.
*
* See the `CompareNEInstruction` documentation for more details.
*/
class CompareNE extends CompareOpcode, TCompareNE {
final override string toString() { result = "CompareNE" }
}
/**
* The `Opcode` for a `CompareLTInstruction`.
*
* See the `CompareLTInstruction` documentation for more details.
*/
class CompareLT extends RelationalOpcode, TCompareLT {
final override string toString() { result = "CompareLT" }
}
/**
* The `Opcode` for a `CompareGTInstruction`.
*
* See the `CompareGTInstruction` documentation for more details.
*/
class CompareGT extends RelationalOpcode, TCompareGT {
final override string toString() { result = "CompareGT" }
}
/**
* The `Opcode` for a `CompareLEInstruction`.
*
* See the `CompareLEInstruction` documentation for more details.
*/
class CompareLE extends RelationalOpcode, TCompareLE {
final override string toString() { result = "CompareLE" }
}
/**
* The `Opcode` for a `CompareGEInstruction`.
*
* See the `CompareGEInstruction` documentation for more details.
*/
class CompareGE extends RelationalOpcode, TCompareGE {
final override string toString() { result = "CompareGE" }
}
/**
* The `Opcode` for a `PointerAddInstruction`.
*
* See the `PointerAddInstruction` documentation for more details.
*/
class PointerAdd extends PointerOffsetOpcode, TPointerAdd {
final override string toString() { result = "PointerAdd" }
}
/**
* The `Opcode` for a `PointerSubInstruction`.
*
* See the `PointerSubInstruction` documentation for more details.
*/
class PointerSub extends PointerOffsetOpcode, TPointerSub {
final override string toString() { result = "PointerSub" }
}
/**
* The `Opcode` for a `PointerDiffInstruction`.
*
* See the `PointerDiffInstruction` documentation for more details.
*/
class PointerDiff extends PointerArithmeticOpcode, TPointerDiff {
final override string toString() { result = "PointerDiff" }
}
/**
* The `Opcode` for a `ConvertInstruction`.
*
* See the `ConvertInstruction` documentation for more details.
*/
class Convert extends UnaryOpcode, TConvert {
final override string toString() { result = "Convert" }
}
/**
* The `Opcode` for a `ConvertToNonVirtualBaseInstruction`.
*
* See the `ConvertToNonVirtualBaseInstruction` documentation for more details.
*/
class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase {
final override string toString() { result = "ConvertToNonVirtualBase" }
}
/**
* The `Opcode` for a `ConvertToVirtualBaseInstruction`.
*
* See the `ConvertToVirtualBaseInstruction` documentation for more details.
*/
class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase {
final override string toString() { result = "ConvertToVirtualBase" }
}
/**
* The `Opcode` for a `ConvertToDerivedInstruction`.
*
* See the `ConvertToDerivedInstruction` documentation for more details.
*/
class ConvertToDerived extends UnaryOpcode, TConvertToDerived {
final override string toString() { result = "ConvertToDerived" }
}
/**
* The `Opcode` for a `CheckedConvertOrNullInstruction`.
*
* See the `CheckedConvertOrNullInstruction` documentation for more details.
*/
class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull {
final override string toString() { result = "CheckedConvertOrNull" }
}
/**
* The `Opcode` for a `CheckedConvertOrThrowInstruction`.
*
* See the `CheckedConvertOrThrowInstruction` documentation for more details.
*/
class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow {
final override string toString() { result = "CheckedConvertOrThrow" }
}
class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid {
final override string toString() { result = "DynamicCastToVoid" }
/**
* The `Opcode` for a `CompleteObjectAddressInstruction`.
*
* See the `CompleteObjectAddressInstruction` documentation for more details.
*/
class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress {
final override string toString() { result = "CompleteObjectAddress" }
}
/**
* The `Opcode` for a `VariableAddressInstruction`.
*
* See the `VariableAddressInstruction` documentation for more details.
*/
class VariableAddress extends Opcode, TVariableAddress {
final override string toString() { result = "VariableAddress" }
}
/**
* The `Opcode` for a `FieldAddressInstruction`.
*
* See the `FieldAddressInstruction` documentation for more details.
*/
class FieldAddress extends UnaryOpcode, TFieldAddress {
final override string toString() { result = "FieldAddress" }
}
/**
* The `Opcode` for an `ElementsAddressInstruction`.
*
* See the `ElementsAddressInstruction` documentation for more details.
*/
class ElementsAddress extends UnaryOpcode, TElementsAddress {
final override string toString() { result = "ElementsAddress" }
}
/**
* The `Opcode` for a `FunctionAddressInstruction`.
*
* See the `FunctionAddressInstruction` documentation for more details.
*/
class FunctionAddress extends Opcode, TFunctionAddress {
final override string toString() { result = "FunctionAddress" }
}
/**
* The `Opcode` for a `ConstantInstruction`.
*
* See the `ConstantInstruction` documentation for more details.
*/
class Constant extends Opcode, TConstant {
final override string toString() { result = "Constant" }
}
/**
* The `Opcode` for a `StringConstantInstruction`.
*
* See the `StringConstantInstruction` documentation for more details.
*/
class StringConstant extends Opcode, TStringConstant {
final override string toString() { result = "StringConstant" }
}
/**
* The `Opcode` for a `ConditionalBranchInstruction`.
*
* See the `ConditionalBranchInstruction` documentation for more details.
*/
class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch {
final override string toString() { result = "ConditionalBranch" }
}
/**
* The `Opcode` for a `SwitchInstruction`.
*
* See the `SwitchInstruction` documentation for more details.
*/
class Switch extends OpcodeWithCondition, TSwitch {
final override string toString() { result = "Switch" }
}
/**
* The `Opcode` for a `CallInstruction`.
*
* See the `CallInstruction` documentation for more details.
*/
class Call extends Opcode, TCall {
final override string toString() { result = "Call" }
@@ -557,32 +926,67 @@ module Opcode {
}
}
/**
* The `Opcode` for a `CatchByTypeInstruction`.
*
* See the `CatchByTypeInstruction` documentation for more details.
*/
class CatchByType extends CatchOpcode, TCatchByType {
final override string toString() { result = "CatchByType" }
}
/**
* The `Opcode` for a `CatchAnyInstruction`.
*
* See the `CatchAnyInstruction` documentation for more details.
*/
class CatchAny extends CatchOpcode, TCatchAny {
final override string toString() { result = "CatchAny" }
}
/**
* The `Opcode` for a `ThrowValueInstruction`.
*
* See the `ThrowValueInstruction` documentation for more details.
*/
class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue {
final override string toString() { result = "ThrowValue" }
}
/**
* The `Opcode` for a `ReThrowInstruction`.
*
* See the `ReThrowInstruction` documentation for more details.
*/
class ReThrow extends ThrowOpcode, TReThrow {
final override string toString() { result = "ReThrow" }
}
/**
* The `Opcode` for an `UnwindInstruction`.
*
* See the `UnwindInstruction` documentation for more details.
*/
class Unwind extends Opcode, TUnwind {
final override string toString() { result = "Unwind" }
}
/**
* The `Opcode` for an `AliasedDefinitionInstruction`.
*
* See the `AliasedDefinitionInstruction` documentation for more details.
*/
class AliasedDefinition extends Opcode, TAliasedDefinition {
final override string toString() { result = "AliasedDefinition" }
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess }
}
/**
* The `Opcode` for an `InitializeNonLocalInstruction`.
*
* See the `InitializeNonLocalInstruction` documentation for more details.
*/
class InitializeNonLocal extends Opcode, TInitializeNonLocal {
final override string toString() { result = "InitializeNonLocal" }
@@ -591,6 +995,11 @@ module Opcode {
}
}
/**
* The `Opcode` for an `AliasedUseInstruction`.
*
* See the `AliasedUseInstruction` documentation for more details.
*/
class AliasedUse extends Opcode, TAliasedUse {
final override string toString() { result = "AliasedUse" }
@@ -601,92 +1010,187 @@ module Opcode {
}
}
/**
* The `Opcode` for a `PhiInstruction`.
*
* See the `PhiInstruction` documentation for more details.
*/
class Phi extends Opcode, TPhi {
final override string toString() { result = "Phi" }
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess }
}
/**
* The `Opcode` for a `BuiltInInstruction`.
*
* See the `BuiltInInstruction` documentation for more details.
*/
class BuiltIn extends BuiltInOperationOpcode, TBuiltIn {
final override string toString() { result = "BuiltIn" }
}
/**
* The `Opcode` for a `VarArgsStartInstruction`.
*
* See the `VarArgsStartInstruction` documentation for more details.
*/
class VarArgsStart extends UnaryOpcode, TVarArgsStart {
final override string toString() { result = "VarArgsStart" }
}
/**
* The `Opcode` for a `VarArgsEndInstruction`.
*
* See the `VarArgsEndInstruction` documentation for more details.
*/
class VarArgsEnd extends UnaryOpcode, TVarArgsEnd {
final override string toString() { result = "VarArgsEnd" }
}
/**
* The `Opcode` for a `VarArgInstruction`.
*
* See the `VarArgInstruction` documentation for more details.
*/
class VarArg extends UnaryOpcode, TVarArg {
final override string toString() { result = "VarArg" }
}
/**
* The `Opcode` for a `NextVarArgInstruction`.
*
* See the `NextVarArgInstruction` documentation for more details.
*/
class NextVarArg extends UnaryOpcode, TNextVarArg {
final override string toString() { result = "NextVarArg" }
}
/**
* The `Opcode` for a `CallSideEffectInstruction`.
*
* See the `CallSideEffectInstruction` documentation for more details.
*/
class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode,
ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect {
final override string toString() { result = "CallSideEffect" }
}
/**
* The `Opcode` for a `CallReadSideEffectInstruction`.
*
* See the `CallReadSideEffectInstruction` documentation for more details.
*/
class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode,
TCallReadSideEffect {
final override string toString() { result = "CallReadSideEffect" }
}
/**
* The `Opcode` for an `IndirectReadSideEffectInstruction`.
*
* See the `IndirectReadSideEffectInstruction` documentation for more details.
*/
class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode,
TIndirectReadSideEffect {
final override string toString() { result = "IndirectReadSideEffect" }
}
/**
* The `Opcode` for an `IndirectMustWriteSideEffectInstruction`.
*
* See the `IndirectMustWriteSideEffectInstruction` documentation for more details.
*/
class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode,
TIndirectMustWriteSideEffect {
final override string toString() { result = "IndirectMustWriteSideEffect" }
}
/**
* The `Opcode` for an `IndirectMayWriteSideEffectInstruction`.
*
* See the `IndirectMayWriteSideEffectInstruction` documentation for more details.
*/
class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode,
MayWriteOpcode, TIndirectMayWriteSideEffect {
final override string toString() { result = "IndirectMayWriteSideEffect" }
}
/**
* The `Opcode` for a `BufferReadSideEffectInstruction`.
*
* See the `BufferReadSideEffectInstruction` documentation for more details.
*/
class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode,
TBufferReadSideEffect {
final override string toString() { result = "BufferReadSideEffect" }
}
/**
* The `Opcode` for a `BufferMustWriteSideEffectInstruction`.
*
* See the `BufferMustWriteSideEffectInstruction` documentation for more details.
*/
class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode,
TBufferMustWriteSideEffect {
final override string toString() { result = "BufferMustWriteSideEffect" }
}
/**
* The `Opcode` for a `BufferMayWriteSideEffectInstruction`.
*
* See the `BufferMayWriteSideEffectInstruction` documentation for more details.
*/
class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode,
MayWriteOpcode, TBufferMayWriteSideEffect {
final override string toString() { result = "BufferMayWriteSideEffect" }
}
/**
* The `Opcode` for a `SizedBufferReadSideEffectInstruction`.
*
* See the `SizedBufferReadSideEffectInstruction` documentation for more details.
*/
class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode,
TSizedBufferReadSideEffect {
final override string toString() { result = "SizedBufferReadSideEffect" }
}
/**
* The `Opcode` for a `SizedBufferMustWriteSideEffectInstruction`.
*
* See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details.
*/
class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode,
TSizedBufferMustWriteSideEffect {
final override string toString() { result = "SizedBufferMustWriteSideEffect" }
}
/**
* The `Opcode` for a `SizedBufferMayWriteSideEffectInstruction`.
*
* See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details.
*/
class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode,
MayWriteOpcode, TSizedBufferMayWriteSideEffect {
final override string toString() { result = "SizedBufferMayWriteSideEffect" }
}
/**
* The `Opcode` for an `InitializeDynamicAllocationInstruction`.
*
* See the `InitializeDynamicAllocationInstruction` documentation for more details.
*/
class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode,
TInitializeDynamicAllocation {
final override string toString() { result = "InitializeDynamicAllocation" }
}
/**
* The `Opcode` for a `ChiInstruction`.
*
* See the `ChiInstruction` documentation for more details.
*/
class Chi extends Opcode, TChi {
final override string toString() { result = "Chi" }
@@ -701,6 +1205,11 @@ module Opcode {
}
}
/**
* The `Opcode` for an `InlineAsmInstruction`.
*
* See the `InlineAsmInstruction` documentation for more details.
*/
class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode,
MayReadOpcode, TInlineAsm {
final override string toString() { result = "InlineAsm" }
@@ -710,10 +1219,20 @@ module Opcode {
}
}
/**
* The `Opcode` for an `UnreachedInstruction`.
*
* See the `UnreachedInstruction` documentation for more details.
*/
class Unreached extends Opcode, TUnreached {
final override string toString() { result = "Unreached" }
}
/**
* The `Opcode` for a `NewObjInstruction`.
*
* See the `NewObjInstruction` documentation for more details.
*/
class NewObj extends Opcode, TNewObj {
final override string toString() { result = "NewObj" }
}

View File

@@ -12,5 +12,6 @@ private import Imports::TempVariableTag
* computed on each branch. The set of possible `TempVariableTag`s is language-dependent.
*/
class TempVariableTag extends TTempVariableTag {
/** Gets a textual representation of this tag. */
string toString() { result = getTempVariableTagId(this) }
}

View File

@@ -1,3 +1,47 @@
/**
* Provides classes that describe the Intermediate Representation (IR) of the program.
*
* The IR is a representation of the semantics of the program, with very little dependence on the
* syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`,
* and `++i` all have the same semantic effect, but appear in the AST as three different types of
* `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental
* operations similar to:
*
* ```
* r1(int*) = VariableAddress[i] // Compute the address of variable `i`
* r2(int) = Load &:r1, m0 // Load the value of `i`
* r3(int) = Constant[1] // An integer constant with the value `1`
* r4(int) = Add r2, r3 // Add `1` to the value of `i`
* r5(int) = Store &r1, r4 // Store the new value back into the variable `i`
* ```
*
* This allows IR-based analysis to focus on the fundamental operations, rather than having to be
* concerned with the various ways of expressing those operations in source code.
*
* The key classes in the IR are:
*
* - `IRFunction` - Contains the IR for an entire function definition, including all of that
* function's `Instruction`s, `IRBlock`s, and `IRVariables`.
* - `Instruction` - A single operation in the IR. An instruction specifies the operation to be
* performed, the operands that produce the inputs to that operation, and the type of the result
* of the operation. Control flows from an `Instruction` to one of a set of successor
* `Instruction`s.
* - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly
* represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has
* a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction`
* that produces its value (its "definition").
* - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is
* created for each variable directly accessed by the function. In addition, `IRVariable`s are
* created to represent certain temporary storage locations that do not have explicitly declared
* variables in the source code, such as the return value of the function.
* - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a
* sequence of instructions such that control flow can only enter the block at the first
* instruction, and can only leave the block from the last instruction.
* - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType`
* is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all
* be represented as the `IRType` `uint4`, a four-byte unsigned integer.
*/
import IRFunction
import Instruction
import IRBlock
@@ -11,11 +55,12 @@ import Imports::MemoryAccessKind
private newtype TIRPropertyProvider = MkIRPropertyProvider()
/**
* Class that provides additional properties to be dumped for IR instructions and blocks when using
* A class that provides additional properties to be dumped for IR instructions and blocks when using
* the PrintIR module. Libraries that compute additional facts about IR elements can extend the
* single instance of this class to specify the additional properties computed by the library.
*/
class IRPropertyProvider extends TIRPropertyProvider {
/** Gets a textual representation of this element. */
string toString() { result = "IRPropertyProvider" }
/**

View File

@@ -1,3 +1,7 @@
/**
* Provides classes describing basic blocks in the IR of a function.
*/
private import internal.IRInternal
import Instruction
private import internal.IRBlockImports as Imports
@@ -16,15 +20,23 @@ private import Cached
* Most consumers should use the class `IRBlock`.
*/
class IRBlockBase extends TIRBlock {
/** Gets a textual representation of this block. */
final string toString() { result = getFirstInstruction(this).toString() }
/** Gets the source location of the first non-`Phi` instruction in this block. */
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
/**
* Gets a string that uniquely identifies this block within its enclosing function.
*
* This predicate is used by debugging and printing code only.
*/
final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() }
/**
* Gets the zero-based index of the block within its function. This is used
* by debugging and printing code only.
* Gets the zero-based index of the block within its function.
*
* This predicate is used by debugging and printing code only.
*/
int getDisplayIndex() {
exists(IRConfiguration::IRConfiguration config |
@@ -42,27 +54,51 @@ class IRBlockBase extends TIRBlock {
)
}
/**
* Gets the `index`th non-`Phi` instruction in this block.
*/
final Instruction getInstruction(int index) { result = getInstruction(this, index) }
/**
* Get the `Phi` instructions that appear at the start of this block.
*/
final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
}
/**
* Get the instructions in this block, including `Phi` instructions.
*/
final Instruction getAnInstruction() {
result = getInstruction(_) or
result = getAPhiInstruction()
}
/**
* Gets the first non-`Phi` instruction in this block.
*/
final Instruction getFirstInstruction() { result = getFirstInstruction(this) }
/**
* Gets the last instruction in this block.
*/
final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) }
/**
* Gets the number of non-`Phi` instructions in this block.
*/
final int getInstructionCount() { result = getInstructionCount(this) }
/**
* Gets the `IRFunction` that contains this block.
*/
final IRFunction getEnclosingIRFunction() {
result = getFirstInstruction(this).getEnclosingIRFunction()
}
/**
* Gets the `Function` that contains this block.
*/
final Language::Function getEnclosingFunction() {
result = getFirstInstruction(this).getEnclosingFunction()
}
@@ -74,20 +110,57 @@ class IRBlockBase extends TIRBlock {
* instruction of another block.
*/
class IRBlock extends IRBlockBase {
/**
* Gets the blocks to which control flows directly from this block.
*/
final IRBlock getASuccessor() { blockSuccessor(this, result) }
/**
* Gets the blocks from which control flows directly to this block.
*/
final IRBlock getAPredecessor() { blockSuccessor(result, this) }
/**
* Gets the block to which control flows directly from this block along an edge of kind `kind`.
*/
final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) }
/**
* Gets the block to which control flows directly from this block along a back edge of kind
* `kind`.
*/
final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) }
/**
* Holds if this block immediately dominates `block`.
*
* Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B`
* is a direct successor of block `A`.
*/
final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) }
/**
* Holds if this block strictly dominates `block`.
*
* Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B`
* are not the same block.
*/
final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) }
/**
* Holds if this block dominates `block`.
*
* Block `A` dominates block `B` if any control flow path from the entry block of the function to
* block `B` must pass through block `A`. A block always dominates itself.
*/
final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block }
/**
* Gets the set of blocks on the dominance frontier of this block.
*
* The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not
* dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`.
*/
pragma[noinline]
final IRBlock dominanceFrontier() {
dominates(result.getAPredecessor()) and
@@ -95,7 +168,7 @@ class IRBlock extends IRBlockBase {
}
/**
* Holds if this block is reachable from the entry point of its function
* Holds if this block is reachable from the entry block of its function.
*/
final predicate isReachableFromFunctionEntry() {
this = getEnclosingIRFunction().getEntryBlock() or
@@ -210,4 +283,4 @@ private module Cached {
idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block)
}
Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) }
private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) }

View File

@@ -1,3 +1,8 @@
/**
* Provides the class `IRFunction`, which represents the Intermediate Representation for the
* definition of a function.
*/
private import internal.IRInternal
private import internal.IRFunctionImports as Imports
import Imports::IRFunctionBase

View File

@@ -1,3 +1,7 @@
/**
* Provides classes that represent variables accessed by the IR.
*/
private import internal.IRInternal
import IRFunction
private import internal.IRVariableImports as Imports
@@ -7,15 +11,11 @@ private import Imports::TTempVariableTag
private import Imports::TIRVariable
private import Imports::IRType
IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) {
result.getVariable() = var and
result.getEnclosingFunction() = func
}
/**
* A variable referenced by the IR for a function. The variable may be a user-declared variable
* (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation
* (`IRTempVariable`).
* A variable referenced by the IR for a function.
*
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
Language::Function func;
@@ -27,6 +27,7 @@ class IRVariable extends TIRVariable {
this = TIRDynamicInitializationFlag(func, _, _)
}
/** Gets a textual representation of this element. */
string toString() { none() }
/**
@@ -162,20 +163,26 @@ class IRGeneratedVariable extends IRVariable {
override string getUniqueId() { none() }
/**
* Gets a string containing the source code location of the AST that generated this variable.
*
* This is used by debugging and printing code only.
*/
final string getLocationString() {
result =
ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
/**
* Gets the string that is combined with the location of the variable to generate the string
* representation of this variable.
*
* This is used by debugging and printing code only.
*/
string getBaseString() { none() }
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
/**
* A temporary variable introduced by IR construction. The most common examples are the variable
* generated to hold the return value of a function, or the variable generated to hold the result of
@@ -190,6 +197,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa
result = "Temp: " + Construction::getTempVariableUniqueId(this)
}
/**
* Gets the "tag" object that differentiates this temporary variable from other temporary
* variables generated for the same AST.
*/
final TempVariableTag getTag() { result = tag }
override string getBaseString() { result = "#temp" }
@@ -253,6 +264,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
final override string getBaseString() { result = "#string" }
/**
* Gets the AST of the string literal represented by this `IRStringLiteral`.
*/
final Language::StringLiteral getLiteral() { result = literal }
}
@@ -270,6 +284,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
final override string toString() { result = var.toString() + "#init" }
/**
* Gets variable whose initialization is guarded by this flag.
*/
final Language::Variable getVariable() { result = var }
final override string getUniqueId() {

View File

@@ -1,3 +1,7 @@
/**
* Provides classes that represent the input values of IR instructions.
*/
private import internal.IRInternal
private import Instruction
private import IRBlock
@@ -78,10 +82,17 @@ private PhiOperandBase phiOperand(
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
*/
class Operand extends TOperand {
/** Gets a textual representation of this element. */
string toString() { result = "Operand" }
/**
* Gets the location of the source code for this operand.
*/
final Language::Location getLocation() { result = getUse().getLocation() }
/**
* Gets the function that contains this operand.
*/
final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() }
/**
@@ -270,6 +281,9 @@ class NonPhiOperand extends Operand {
final override int getDumpSortOrder() { result = tag.getSortOrder() }
/**
* Gets the `OperandTag` that specifies how this operand is used by its `Instruction`.
*/
final OperandTag getOperandTag() { result = tag }
}
@@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
}
}
/**
* A memory operand other than the operand of a `Phi` instruction.
*/
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase {
override MemoryOperandTag tag;
@@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper
}
}
/**
* A memory operand whose type may be different from the type of the result of its definition.
*/
class TypedOperand extends NonPhiMemoryOperand {
override TypedOperandTag tag;
@@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand {
final int getIndex() { result = tag.getArgIndex() }
}
/**
* An operand representing memory read as a side effect of evaluating another instruction.
*/
class SideEffectOperand extends TypedOperand {
override SideEffectOperandTag tag;
}

View File

@@ -1,3 +1,13 @@
/**
* Outputs a representation of the IR as a control flow graph.
*
* This file contains the actual implementation of `PrintIR.ql`. For test cases and very small
* databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
* `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to
* dump.
*/
private import internal.IRInternal
private import IR
private import internal.PrintIRImports as Imports
@@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
* The query can extend this class to control which functions are printed.
*/
class PrintIRConfiguration extends TPrintIRConfiguration {
/** Gets a textual representation of this configuration. */
string toString() { result = "PrintIRConfiguration" }
/**
@@ -47,7 +58,7 @@ private newtype TPrintableIRNode =
/**
* A node to be emitted in the IR graph.
*/
abstract class PrintableIRNode extends TPrintableIRNode {
abstract private class PrintableIRNode extends TPrintableIRNode {
abstract string toString();
/**
@@ -98,7 +109,7 @@ abstract class PrintableIRNode extends TPrintableIRNode {
/**
* An IR graph node representing a `IRFunction` object.
*/
class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
IRFunction irFunc;
PrintableIRFunction() { this = TPrintableIRFunction(irFunc) }
@@ -129,7 +140,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
/**
* An IR graph node representing an `IRBlock` object.
*/
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
IRBlock block;
PrintableIRBlock() { this = TPrintableIRBlock(block) }
@@ -161,7 +172,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
/**
* An IR graph node representing an `Instruction`.
*/
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
Instruction instr;
PrintableInstruction() { this = TPrintableInstruction(instr) }
@@ -224,6 +235,9 @@ private string getPaddingString(int n) {
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
}
/**
* Holds if `node` belongs to the output graph, and its property `key` has the given `value`.
*/
query predicate nodes(PrintableIRNode node, string key, string value) {
value = node.getProperty(key)
}
@@ -237,6 +251,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
)
}
/**
* Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key`
* has the given `value`.
*/
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
predBlock = pred.getBlock() and
@@ -256,6 +274,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
)
}
/**
* Holds if `parent` is the parent node of `child` in the output graph.
*/
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
parent = child.getParent()
}

View File

@@ -21,6 +21,16 @@ ArrayType getArrayOfDim(int dim, Type type) {
result.getElementType() = type
}
IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) {
result.getVariable() = var and
result.getEnclosingFunction() = func
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
private predicate canCreateCompilerGeneratedElement(Element generatedBy, int nth) {
generatedBy instanceof ForeachStmt and nth in [0 .. ForeachElements::noGeneratedElements() - 1]
or

View File

@@ -1,3 +1,47 @@
/**
* Provides classes that describe the Intermediate Representation (IR) of the program.
*
* The IR is a representation of the semantics of the program, with very little dependence on the
* syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`,
* and `++i` all have the same semantic effect, but appear in the AST as three different types of
* `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental
* operations similar to:
*
* ```
* r1(int*) = VariableAddress[i] // Compute the address of variable `i`
* r2(int) = Load &:r1, m0 // Load the value of `i`
* r3(int) = Constant[1] // An integer constant with the value `1`
* r4(int) = Add r2, r3 // Add `1` to the value of `i`
* r5(int) = Store &r1, r4 // Store the new value back into the variable `i`
* ```
*
* This allows IR-based analysis to focus on the fundamental operations, rather than having to be
* concerned with the various ways of expressing those operations in source code.
*
* The key classes in the IR are:
*
* - `IRFunction` - Contains the IR for an entire function definition, including all of that
* function's `Instruction`s, `IRBlock`s, and `IRVariables`.
* - `Instruction` - A single operation in the IR. An instruction specifies the operation to be
* performed, the operands that produce the inputs to that operation, and the type of the result
* of the operation. Control flows from an `Instruction` to one of a set of successor
* `Instruction`s.
* - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly
* represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has
* a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction`
* that produces its value (its "definition").
* - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is
* created for each variable directly accessed by the function. In addition, `IRVariable`s are
* created to represent certain temporary storage locations that do not have explicitly declared
* variables in the source code, such as the return value of the function.
* - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a
* sequence of instructions such that control flow can only enter the block at the first
* instruction, and can only leave the block from the last instruction.
* - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType`
* is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all
* be represented as the `IRType` `uint4`, a four-byte unsigned integer.
*/
import IRFunction
import Instruction
import IRBlock
@@ -11,11 +55,12 @@ import Imports::MemoryAccessKind
private newtype TIRPropertyProvider = MkIRPropertyProvider()
/**
* Class that provides additional properties to be dumped for IR instructions and blocks when using
* A class that provides additional properties to be dumped for IR instructions and blocks when using
* the PrintIR module. Libraries that compute additional facts about IR elements can extend the
* single instance of this class to specify the additional properties computed by the library.
*/
class IRPropertyProvider extends TIRPropertyProvider {
/** Gets a textual representation of this element. */
string toString() { result = "IRPropertyProvider" }
/**

View File

@@ -1,3 +1,7 @@
/**
* Provides classes describing basic blocks in the IR of a function.
*/
private import internal.IRInternal
import Instruction
private import internal.IRBlockImports as Imports
@@ -16,15 +20,23 @@ private import Cached
* Most consumers should use the class `IRBlock`.
*/
class IRBlockBase extends TIRBlock {
/** Gets a textual representation of this block. */
final string toString() { result = getFirstInstruction(this).toString() }
/** Gets the source location of the first non-`Phi` instruction in this block. */
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
/**
* Gets a string that uniquely identifies this block within its enclosing function.
*
* This predicate is used by debugging and printing code only.
*/
final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() }
/**
* Gets the zero-based index of the block within its function. This is used
* by debugging and printing code only.
* Gets the zero-based index of the block within its function.
*
* This predicate is used by debugging and printing code only.
*/
int getDisplayIndex() {
exists(IRConfiguration::IRConfiguration config |
@@ -42,27 +54,51 @@ class IRBlockBase extends TIRBlock {
)
}
/**
* Gets the `index`th non-`Phi` instruction in this block.
*/
final Instruction getInstruction(int index) { result = getInstruction(this, index) }
/**
* Get the `Phi` instructions that appear at the start of this block.
*/
final PhiInstruction getAPhiInstruction() {
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
}
/**
* Get the instructions in this block, including `Phi` instructions.
*/
final Instruction getAnInstruction() {
result = getInstruction(_) or
result = getAPhiInstruction()
}
/**
* Gets the first non-`Phi` instruction in this block.
*/
final Instruction getFirstInstruction() { result = getFirstInstruction(this) }
/**
* Gets the last instruction in this block.
*/
final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) }
/**
* Gets the number of non-`Phi` instructions in this block.
*/
final int getInstructionCount() { result = getInstructionCount(this) }
/**
* Gets the `IRFunction` that contains this block.
*/
final IRFunction getEnclosingIRFunction() {
result = getFirstInstruction(this).getEnclosingIRFunction()
}
/**
* Gets the `Function` that contains this block.
*/
final Language::Function getEnclosingFunction() {
result = getFirstInstruction(this).getEnclosingFunction()
}
@@ -74,20 +110,57 @@ class IRBlockBase extends TIRBlock {
* instruction of another block.
*/
class IRBlock extends IRBlockBase {
/**
* Gets the blocks to which control flows directly from this block.
*/
final IRBlock getASuccessor() { blockSuccessor(this, result) }
/**
* Gets the blocks from which control flows directly to this block.
*/
final IRBlock getAPredecessor() { blockSuccessor(result, this) }
/**
* Gets the block to which control flows directly from this block along an edge of kind `kind`.
*/
final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) }
/**
* Gets the block to which control flows directly from this block along a back edge of kind
* `kind`.
*/
final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) }
/**
* Holds if this block immediately dominates `block`.
*
* Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B`
* is a direct successor of block `A`.
*/
final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) }
/**
* Holds if this block strictly dominates `block`.
*
* Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B`
* are not the same block.
*/
final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) }
/**
* Holds if this block dominates `block`.
*
* Block `A` dominates block `B` if any control flow path from the entry block of the function to
* block `B` must pass through block `A`. A block always dominates itself.
*/
final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block }
/**
* Gets the set of blocks on the dominance frontier of this block.
*
* The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not
* dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`.
*/
pragma[noinline]
final IRBlock dominanceFrontier() {
dominates(result.getAPredecessor()) and
@@ -95,7 +168,7 @@ class IRBlock extends IRBlockBase {
}
/**
* Holds if this block is reachable from the entry point of its function
* Holds if this block is reachable from the entry block of its function.
*/
final predicate isReachableFromFunctionEntry() {
this = getEnclosingIRFunction().getEntryBlock() or
@@ -210,4 +283,4 @@ private module Cached {
idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block)
}
Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) }
private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) }

View File

@@ -1,3 +1,8 @@
/**
* Provides the class `IRFunction`, which represents the Intermediate Representation for the
* definition of a function.
*/
private import internal.IRInternal
private import internal.IRFunctionImports as Imports
import Imports::IRFunctionBase

View File

@@ -1,3 +1,7 @@
/**
* Provides classes that represent variables accessed by the IR.
*/
private import internal.IRInternal
import IRFunction
private import internal.IRVariableImports as Imports
@@ -7,15 +11,11 @@ private import Imports::TTempVariableTag
private import Imports::TIRVariable
private import Imports::IRType
IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) {
result.getVariable() = var and
result.getEnclosingFunction() = func
}
/**
* A variable referenced by the IR for a function. The variable may be a user-declared variable
* (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation
* (`IRTempVariable`).
* A variable referenced by the IR for a function.
*
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
* by the AST-to-IR translation (`IRTempVariable`).
*/
class IRVariable extends TIRVariable {
Language::Function func;
@@ -27,6 +27,7 @@ class IRVariable extends TIRVariable {
this = TIRDynamicInitializationFlag(func, _, _)
}
/** Gets a textual representation of this element. */
string toString() { none() }
/**
@@ -162,20 +163,26 @@ class IRGeneratedVariable extends IRVariable {
override string getUniqueId() { none() }
/**
* Gets a string containing the source code location of the AST that generated this variable.
*
* This is used by debugging and printing code only.
*/
final string getLocationString() {
result =
ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
/**
* Gets the string that is combined with the location of the variable to generate the string
* representation of this variable.
*
* This is used by debugging and printing code only.
*/
string getBaseString() { none() }
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
/**
* A temporary variable introduced by IR construction. The most common examples are the variable
* generated to hold the return value of a function, or the variable generated to hold the result of
@@ -190,6 +197,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa
result = "Temp: " + Construction::getTempVariableUniqueId(this)
}
/**
* Gets the "tag" object that differentiates this temporary variable from other temporary
* variables generated for the same AST.
*/
final TempVariableTag getTag() { result = tag }
override string getBaseString() { result = "#temp" }
@@ -253,6 +264,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
final override string getBaseString() { result = "#string" }
/**
* Gets the AST of the string literal represented by this `IRStringLiteral`.
*/
final Language::StringLiteral getLiteral() { result = literal }
}
@@ -270,6 +284,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
final override string toString() { result = var.toString() + "#init" }
/**
* Gets variable whose initialization is guarded by this flag.
*/
final Language::Variable getVariable() { result = var }
final override string getUniqueId() {

View File

@@ -1,3 +1,7 @@
/**
* Provides classes that represent the input values of IR instructions.
*/
private import internal.IRInternal
private import Instruction
private import IRBlock
@@ -78,10 +82,17 @@ private PhiOperandBase phiOperand(
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
*/
class Operand extends TOperand {
/** Gets a textual representation of this element. */
string toString() { result = "Operand" }
/**
* Gets the location of the source code for this operand.
*/
final Language::Location getLocation() { result = getUse().getLocation() }
/**
* Gets the function that contains this operand.
*/
final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() }
/**
@@ -270,6 +281,9 @@ class NonPhiOperand extends Operand {
final override int getDumpSortOrder() { result = tag.getSortOrder() }
/**
* Gets the `OperandTag` that specifies how this operand is used by its `Instruction`.
*/
final OperandTag getOperandTag() { result = tag }
}
@@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
}
}
/**
* A memory operand other than the operand of a `Phi` instruction.
*/
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase {
override MemoryOperandTag tag;
@@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper
}
}
/**
* A memory operand whose type may be different from the type of the result of its definition.
*/
class TypedOperand extends NonPhiMemoryOperand {
override TypedOperandTag tag;
@@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand {
final int getIndex() { result = tag.getArgIndex() }
}
/**
* An operand representing memory read as a side effect of evaluating another instruction.
*/
class SideEffectOperand extends TypedOperand {
override SideEffectOperandTag tag;
}

View File

@@ -1,3 +1,13 @@
/**
* Outputs a representation of the IR as a control flow graph.
*
* This file contains the actual implementation of `PrintIR.ql`. For test cases and very small
* databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
* `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to
* dump.
*/
private import internal.IRInternal
private import IR
private import internal.PrintIRImports as Imports
@@ -9,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
* The query can extend this class to control which functions are printed.
*/
class PrintIRConfiguration extends TPrintIRConfiguration {
/** Gets a textual representation of this configuration. */
string toString() { result = "PrintIRConfiguration" }
/**
@@ -47,7 +58,7 @@ private newtype TPrintableIRNode =
/**
* A node to be emitted in the IR graph.
*/
abstract class PrintableIRNode extends TPrintableIRNode {
abstract private class PrintableIRNode extends TPrintableIRNode {
abstract string toString();
/**
@@ -98,7 +109,7 @@ abstract class PrintableIRNode extends TPrintableIRNode {
/**
* An IR graph node representing a `IRFunction` object.
*/
class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
IRFunction irFunc;
PrintableIRFunction() { this = TPrintableIRFunction(irFunc) }
@@ -129,7 +140,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
/**
* An IR graph node representing an `IRBlock` object.
*/
class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
IRBlock block;
PrintableIRBlock() { this = TPrintableIRBlock(block) }
@@ -161,7 +172,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
/**
* An IR graph node representing an `Instruction`.
*/
class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
Instruction instr;
PrintableInstruction() { this = TPrintableInstruction(instr) }
@@ -224,6 +235,9 @@ private string getPaddingString(int n) {
n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " "
}
/**
* Holds if `node` belongs to the output graph, and its property `key` has the given `value`.
*/
query predicate nodes(PrintableIRNode node, string key, string value) {
value = node.getProperty(key)
}
@@ -237,6 +251,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) {
)
}
/**
* Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key`
* has the given `value`.
*/
query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) {
exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock |
predBlock = pred.getBlock() and
@@ -256,6 +274,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key,
)
}
/**
* Holds if `parent` is the parent node of `child` in the output graph.
*/
query predicate parents(PrintableIRNode child, PrintableIRNode parent) {
parent = child.getParent()
}

View File

@@ -68,7 +68,7 @@ module Stages {
or
exists(any(DataFlow::Node n).getType())
or
exists(any(DataFlow::Node n).getTypeBound())
exists(any(NodeImpl n).getDataFlowType())
or
exists(any(DataFlow::Node n).getLocation())
or

View File

@@ -67,7 +67,6 @@ private predicate transitiveCapturedCallTarget(ControlFlow::Nodes::ElementNode c
cached
private module Cached {
private import CallContext
private import semmle.code.csharp.Caching
cached
@@ -107,7 +106,13 @@ private module Cached {
/** Gets a viable run-time target for the call `call`. */
cached
DataFlowCallable viableImpl(DataFlowCall call) { result = call.getARuntimeTarget() }
DataFlowCallable viableCallable(DataFlowCall call) { result = call.getARuntimeTarget() }
}
import Cached
private module DispatchImpl {
private import CallContext
/**
* Gets a viable run-time target for the delegate call `call`, requiring
@@ -123,7 +128,7 @@ private module Cached {
* call is a delegate call, or if the qualifier accesses a parameter of
* the enclosing callable `c` (including the implicit `this` parameter).
*/
private predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) {
predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) {
c = call.getEnclosingCallable() and
(
exists(CallContext cc | exists(viableDelegateCallable(call, cc)) |
@@ -134,26 +139,11 @@ private module Cached {
)
}
/**
* Holds if the call context `ctx` reduces the set of viable run-time
* targets of call `call` in `c`.
*/
cached
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
exists(int tgts, int ctxtgts |
mayBenefitFromCallContext(call, c) and
c = viableCallable(ctx) and
ctxtgts = count(viableImplInCallContext(call, ctx)) and
tgts = strictcount(viableImpl(call)) and
ctxtgts < tgts
)
}
/**
* Gets a viable dispatch target of `call` in the context `ctx`. This is
* restricted to those `call`s for which a context might make a difference.
*/
private DotNet::Callable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
DotNet::Callable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) |
cc.isArgument(ctx.getExpr(), _)
)
@@ -164,47 +154,9 @@ private module Cached {
.getDispatchCall()
.getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall())
}
/**
* Gets a viable run-time target for the call `call` in the context
* `ctx`. This is restricted to those call nodes for which a context
* might make a difference.
*/
cached
DotNet::Callable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx) and
reducedViableImplInCallContext(call, _, ctx)
}
/**
* Holds if flow returning from callable `c` to call `call` might return
* further and if this path restricts the set of call sites that can be
* returned to.
*/
cached
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
exists(int tgts, int ctxtgts |
mayBenefitFromCallContext(call, _) and
c = viableImpl(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
ctxtgts < tgts
)
}
/**
* Gets a viable run-time target for the call `call` in the context `ctx`.
* This is restricted to those call nodes and results for which the return
* flow from the result to `call` restricts the possible context `ctx`.
*/
cached
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx) and
reducedViableImplInReturn(result, call)
}
}
import Cached
import DispatchImpl
/**
* Gets a node that can read the value returned from `call` with return kind
@@ -212,8 +164,6 @@ import Cached
*/
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { call = result.getCall(kind) }
predicate viableCallable = viableImpl/1;
/**
* A return kind. A return kind describes how a value can be returned
* from a callable.

View File

@@ -1124,11 +1124,11 @@ private module LocalFlowBigStep {
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
t = getNodeType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
t = getNodeType(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1147,7 +1147,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
t = getNodeType(node2) and
nodeCand2(node2, unbind(config))
)
)
@@ -1202,9 +1202,7 @@ private predicate flowCandFwd(
) {
flowCandFwd0(node, fromArg, argApf, apf, config) and
not apf.isClearedAt(node) and
if node instanceof CastingNode
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
else any()
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
}
pragma[nomagic]
@@ -1216,7 +1214,7 @@ private predicate flowCandFwd0(
config.isSource(node) and
fromArg = false and
argApf = TAccessPathFrontNone() and
apf = TFrontNil(getErasedNodeTypeBound(node))
apf = TFrontNil(getNodeType(node))
or
exists(Node mid |
flowCandFwd(mid, fromArg, argApf, apf, config) and
@@ -1242,7 +1240,7 @@ private predicate flowCandFwd0(
additionalJumpStep(mid, node, config) and
fromArg = false and
argApf = TAccessPathFrontNone() and
apf = TFrontNil(getErasedNodeTypeBound(node))
apf = TFrontNil(getNodeType(node))
)
or
// store
@@ -1672,7 +1670,7 @@ private predicate flowFwd0(
config.isSource(node) and
fromArg = false and
argAp = TAccessPathNone() and
ap = TNil(getErasedNodeTypeBound(node)) and
ap = TNil(getNodeType(node)) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, _, unbind(config)) and
@@ -1700,7 +1698,7 @@ private predicate flowFwd0(
additionalJumpStep(mid, node, config) and
fromArg = false and
argAp = TAccessPathNone() and
ap = TNil(getErasedNodeTypeBound(node)) and
ap = TNil(getNodeType(node)) and
apf = ap.(AccessPathNil).getFront()
)
)
@@ -2077,7 +2075,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TNil(getErasedNodeTypeBound(node))
ap = TNil(getNodeType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
ap = TNil(getNodeType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -2646,7 +2644,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -2663,7 +2661,7 @@ private module FlowExploration {
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
then compatibleTypes(getNodeType(node), ap.getType())
else any()
)
}
@@ -2776,7 +2774,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
config = mid.getConfiguration()
)
or
@@ -2792,7 +2790,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -2806,7 +2804,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
compatibleTypes(ap.getType(), getNodeType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)

View File

@@ -1124,11 +1124,11 @@ private module LocalFlowBigStep {
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
t = getNodeType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
t = getNodeType(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1147,7 +1147,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
t = getNodeType(node2) and
nodeCand2(node2, unbind(config))
)
)
@@ -1202,9 +1202,7 @@ private predicate flowCandFwd(
) {
flowCandFwd0(node, fromArg, argApf, apf, config) and
not apf.isClearedAt(node) and
if node instanceof CastingNode
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
else any()
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
}
pragma[nomagic]
@@ -1216,7 +1214,7 @@ private predicate flowCandFwd0(
config.isSource(node) and
fromArg = false and
argApf = TAccessPathFrontNone() and
apf = TFrontNil(getErasedNodeTypeBound(node))
apf = TFrontNil(getNodeType(node))
or
exists(Node mid |
flowCandFwd(mid, fromArg, argApf, apf, config) and
@@ -1242,7 +1240,7 @@ private predicate flowCandFwd0(
additionalJumpStep(mid, node, config) and
fromArg = false and
argApf = TAccessPathFrontNone() and
apf = TFrontNil(getErasedNodeTypeBound(node))
apf = TFrontNil(getNodeType(node))
)
or
// store
@@ -1672,7 +1670,7 @@ private predicate flowFwd0(
config.isSource(node) and
fromArg = false and
argAp = TAccessPathNone() and
ap = TNil(getErasedNodeTypeBound(node)) and
ap = TNil(getNodeType(node)) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, _, unbind(config)) and
@@ -1700,7 +1698,7 @@ private predicate flowFwd0(
additionalJumpStep(mid, node, config) and
fromArg = false and
argAp = TAccessPathNone() and
ap = TNil(getErasedNodeTypeBound(node)) and
ap = TNil(getNodeType(node)) and
apf = ap.(AccessPathNil).getFront()
)
)
@@ -2077,7 +2075,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TNil(getErasedNodeTypeBound(node))
ap = TNil(getNodeType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
ap = TNil(getNodeType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -2646,7 +2644,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -2663,7 +2661,7 @@ private module FlowExploration {
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
then compatibleTypes(getNodeType(node), ap.getType())
else any()
)
}
@@ -2776,7 +2774,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
config = mid.getConfiguration()
)
or
@@ -2792,7 +2790,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -2806,7 +2804,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
compatibleTypes(ap.getType(), getNodeType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)

View File

@@ -1124,11 +1124,11 @@ private module LocalFlowBigStep {
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
t = getNodeType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
t = getNodeType(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1147,7 +1147,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
t = getNodeType(node2) and
nodeCand2(node2, unbind(config))
)
)
@@ -1202,9 +1202,7 @@ private predicate flowCandFwd(
) {
flowCandFwd0(node, fromArg, argApf, apf, config) and
not apf.isClearedAt(node) and
if node instanceof CastingNode
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
else any()
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
}
pragma[nomagic]
@@ -1216,7 +1214,7 @@ private predicate flowCandFwd0(
config.isSource(node) and
fromArg = false and
argApf = TAccessPathFrontNone() and
apf = TFrontNil(getErasedNodeTypeBound(node))
apf = TFrontNil(getNodeType(node))
or
exists(Node mid |
flowCandFwd(mid, fromArg, argApf, apf, config) and
@@ -1242,7 +1240,7 @@ private predicate flowCandFwd0(
additionalJumpStep(mid, node, config) and
fromArg = false and
argApf = TAccessPathFrontNone() and
apf = TFrontNil(getErasedNodeTypeBound(node))
apf = TFrontNil(getNodeType(node))
)
or
// store
@@ -1672,7 +1670,7 @@ private predicate flowFwd0(
config.isSource(node) and
fromArg = false and
argAp = TAccessPathNone() and
ap = TNil(getErasedNodeTypeBound(node)) and
ap = TNil(getNodeType(node)) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, _, unbind(config)) and
@@ -1700,7 +1698,7 @@ private predicate flowFwd0(
additionalJumpStep(mid, node, config) and
fromArg = false and
argAp = TAccessPathNone() and
ap = TNil(getErasedNodeTypeBound(node)) and
ap = TNil(getNodeType(node)) and
apf = ap.(AccessPathNil).getFront()
)
)
@@ -2077,7 +2075,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TNil(getErasedNodeTypeBound(node))
ap = TNil(getNodeType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
ap = TNil(getNodeType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -2646,7 +2644,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -2663,7 +2661,7 @@ private module FlowExploration {
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
then compatibleTypes(getNodeType(node), ap.getType())
else any()
)
}
@@ -2776,7 +2774,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
config = mid.getConfiguration()
)
or
@@ -2792,7 +2790,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -2806,7 +2804,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
compatibleTypes(ap.getType(), getNodeType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)

View File

@@ -1124,11 +1124,11 @@ private module LocalFlowBigStep {
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
t = getNodeType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
t = getNodeType(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1147,7 +1147,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
t = getNodeType(node2) and
nodeCand2(node2, unbind(config))
)
)
@@ -1202,9 +1202,7 @@ private predicate flowCandFwd(
) {
flowCandFwd0(node, fromArg, argApf, apf, config) and
not apf.isClearedAt(node) and
if node instanceof CastingNode
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
else any()
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
}
pragma[nomagic]
@@ -1216,7 +1214,7 @@ private predicate flowCandFwd0(
config.isSource(node) and
fromArg = false and
argApf = TAccessPathFrontNone() and
apf = TFrontNil(getErasedNodeTypeBound(node))
apf = TFrontNil(getNodeType(node))
or
exists(Node mid |
flowCandFwd(mid, fromArg, argApf, apf, config) and
@@ -1242,7 +1240,7 @@ private predicate flowCandFwd0(
additionalJumpStep(mid, node, config) and
fromArg = false and
argApf = TAccessPathFrontNone() and
apf = TFrontNil(getErasedNodeTypeBound(node))
apf = TFrontNil(getNodeType(node))
)
or
// store
@@ -1672,7 +1670,7 @@ private predicate flowFwd0(
config.isSource(node) and
fromArg = false and
argAp = TAccessPathNone() and
ap = TNil(getErasedNodeTypeBound(node)) and
ap = TNil(getNodeType(node)) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, _, unbind(config)) and
@@ -1700,7 +1698,7 @@ private predicate flowFwd0(
additionalJumpStep(mid, node, config) and
fromArg = false and
argAp = TAccessPathNone() and
ap = TNil(getErasedNodeTypeBound(node)) and
ap = TNil(getNodeType(node)) and
apf = ap.(AccessPathNil).getFront()
)
)
@@ -2077,7 +2075,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TNil(getErasedNodeTypeBound(node))
ap = TNil(getNodeType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
ap = TNil(getNodeType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -2646,7 +2644,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -2663,7 +2661,7 @@ private module FlowExploration {
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
then compatibleTypes(getNodeType(node), ap.getType())
else any()
)
}
@@ -2776,7 +2774,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
config = mid.getConfiguration()
)
or
@@ -2792,7 +2790,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -2806,7 +2804,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
compatibleTypes(ap.getType(), getNodeType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)

View File

@@ -1124,11 +1124,11 @@ private module LocalFlowBigStep {
(
localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and
t = getErasedNodeTypeBound(node1)
t = getNodeType(node1)
or
additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and
t = getErasedNodeTypeBound(node2)
t = getNodeType(node2)
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
@@ -1147,7 +1147,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = getErasedNodeTypeBound(node2) and
t = getNodeType(node2) and
nodeCand2(node2, unbind(config))
)
)
@@ -1202,9 +1202,7 @@ private predicate flowCandFwd(
) {
flowCandFwd0(node, fromArg, argApf, apf, config) and
not apf.isClearedAt(node) and
if node instanceof CastingNode
then compatibleTypes(getErasedNodeTypeBound(node), apf.getType())
else any()
if node instanceof CastingNode then compatibleTypes(getNodeType(node), apf.getType()) else any()
}
pragma[nomagic]
@@ -1216,7 +1214,7 @@ private predicate flowCandFwd0(
config.isSource(node) and
fromArg = false and
argApf = TAccessPathFrontNone() and
apf = TFrontNil(getErasedNodeTypeBound(node))
apf = TFrontNil(getNodeType(node))
or
exists(Node mid |
flowCandFwd(mid, fromArg, argApf, apf, config) and
@@ -1242,7 +1240,7 @@ private predicate flowCandFwd0(
additionalJumpStep(mid, node, config) and
fromArg = false and
argApf = TAccessPathFrontNone() and
apf = TFrontNil(getErasedNodeTypeBound(node))
apf = TFrontNil(getNodeType(node))
)
or
// store
@@ -1672,7 +1670,7 @@ private predicate flowFwd0(
config.isSource(node) and
fromArg = false and
argAp = TAccessPathNone() and
ap = TNil(getErasedNodeTypeBound(node)) and
ap = TNil(getNodeType(node)) and
apf = ap.(AccessPathNil).getFront()
or
flowCand(node, _, _, _, unbind(config)) and
@@ -1700,7 +1698,7 @@ private predicate flowFwd0(
additionalJumpStep(mid, node, config) and
fromArg = false and
argAp = TAccessPathNone() and
ap = TNil(getErasedNodeTypeBound(node)) and
ap = TNil(getNodeType(node)) and
apf = ap.(AccessPathNil).getFront()
)
)
@@ -2077,7 +2075,7 @@ private newtype TPathNode =
config.isSource(node) and
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
ap = TNil(getErasedNodeTypeBound(node))
ap = TNil(getNodeType(node))
or
// ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid |
@@ -2304,7 +2302,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and
ap = TNil(getErasedNodeTypeBound(node))
ap = TNil(getNodeType(node))
or
exists(TypedContent tc | pathStoreStep(mid, node, pop(tc, ap), tc, cc)) and
sc = mid.getSummaryCtx()
@@ -2646,7 +2644,7 @@ private module FlowExploration {
cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
not fullBarrier(node, config) and
exists(config.explorationLimit())
or
@@ -2663,7 +2661,7 @@ private module FlowExploration {
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and
if node instanceof CastingNode
then compatibleTypes(getErasedNodeTypeBound(node), ap.getType())
then compatibleTypes(getNodeType(node), ap.getType())
else any()
)
}
@@ -2776,7 +2774,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
config = mid.getConfiguration()
)
or
@@ -2792,7 +2790,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedNodeTypeBound(node)) and
ap = TPartialNil(getNodeType(node)) and
config = mid.getConfiguration()
or
partialPathStoreStep(mid, _, _, node, ap) and
@@ -2806,7 +2804,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getErasedNodeTypeBound(node))
compatibleTypes(ap.getType(), getNodeType(node))
)
or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)

View File

@@ -22,7 +22,7 @@ private module Cached {
exists(int i |
viableParam(call, i, p) and
arg.argumentOf(call, i) and
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(p))
compatibleTypes(getNodeType(arg), getNodeType(p))
)
}
@@ -218,10 +218,10 @@ private module Cached {
then
// normal flow through
read = TReadStepTypesNone() and
compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node))
compatibleTypes(getNodeType(p), getNodeType(node))
or
// getter
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(node))
compatibleTypes(read.getContentType(), getNodeType(node))
else any()
}
@@ -243,7 +243,7 @@ private module Cached {
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and
compatibleTypes(getErasedNodeTypeBound(p), read.getContainerType())
compatibleTypes(getNodeType(p), read.getContainerType())
)
or
// flow through: no prior read
@@ -292,11 +292,11 @@ private module Cached {
|
// normal flow through
read = TReadStepTypesNone() and
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out))
compatibleTypes(getNodeType(arg), getNodeType(out))
or
// getter
compatibleTypes(getErasedNodeTypeBound(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getErasedNodeTypeBound(out))
compatibleTypes(getNodeType(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getNodeType(out))
)
}
@@ -330,6 +330,67 @@ private module Cached {
import Final
}
import FlowThrough
cached
private module DispatchWithCallContext {
/**
* Holds if the call context `ctx` reduces the set of viable run-time
* dispatch targets of call `call` in `c`.
*/
cached
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
exists(int tgts, int ctxtgts |
mayBenefitFromCallContext(call, c) and
c = viableCallable(ctx) and
ctxtgts = count(viableImplInCallContext(call, ctx)) and
tgts = strictcount(viableCallable(call)) and
ctxtgts < tgts
)
}
/**
* Gets a viable run-time dispatch target for the call `call` in the
* context `ctx`. This is restricted to those calls for which a context
* makes a difference.
*/
cached
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx) and
reducedViableImplInCallContext(call, _, ctx)
}
/**
* Holds if flow returning from callable `c` to call `call` might return
* further and if this path restricts the set of call sites that can be
* returned to.
*/
cached
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
exists(int tgts, int ctxtgts |
mayBenefitFromCallContext(call, _) and
c = viableCallable(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
ctxtgts < tgts
)
}
/**
* Gets a viable run-time dispatch target for the call `call` in the
* context `ctx`. This is restricted to those calls and results for which
* the return flow from the result to `call` restricts the possible context
* `ctx`.
*/
cached
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
result = viableImplInCallContext(call, ctx) and
reducedViableImplInReturn(result, call)
}
}
import DispatchWithCallContext
/**
* Holds if `p` can flow to the pre-update node associated with post-update
* node `n`, in the same callable, using only value-preserving steps.
@@ -344,8 +405,8 @@ private module Cached {
) {
storeStep(node1, c, node2) and
readStep(_, c, _) and
contentType = getErasedNodeTypeBound(node1) and
containerType = getErasedNodeTypeBound(node2)
contentType = getNodeType(node1) and
containerType = getNodeType(node2)
or
exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
@@ -354,8 +415,8 @@ private module Cached {
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
readStep(n2, c, n1) and
contentType = getErasedNodeTypeBound(n1) and
containerType = getErasedNodeTypeBound(n2)
contentType = getNodeType(n1) and
containerType = getNodeType(n2)
)
}
@@ -371,8 +432,6 @@ private module Cached {
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
}
import FlowThrough
/**
* Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -448,8 +507,8 @@ private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) {
readStep(n1, c, n2) and
container = getErasedNodeTypeBound(n1) and
content = getErasedNodeTypeBound(n2)
container = getNodeType(n1) and
content = getNodeType(n2)
}
private newtype TReadStepTypesOption =
@@ -712,9 +771,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
result = viableCallable(call) and cc instanceof CallContextReturn
}
pragma[noinline]
DataFlowType getErasedNodeTypeBound(Node n) { result = getErasedRepr(n.getTypeBound()) }
predicate read = readStep/3;
/** An optional Boolean value. */

View File

@@ -37,21 +37,12 @@ module Consistency {
)
}
query predicate uniqueTypeBound(Node n, string msg) {
query predicate uniqueType(Node n, string msg) {
exists(int c |
n instanceof RelevantNode and
c = count(n.getTypeBound()) and
c = count(getNodeType(n)) and
c != 1 and
msg = "Node should have one type bound but has " + c + "."
)
}
query predicate uniqueTypeRepr(Node n, string msg) {
exists(int c |
n instanceof RelevantNode and
c = count(getErasedRepr(n.getTypeBound())) and
c != 1 and
msg = "Node should have one type representation but has " + c + "."
msg = "Node should have one type but has " + c + "."
)
}
@@ -104,7 +95,7 @@ module Consistency {
msg = "Local flow step does not preserve enclosing callable."
}
private DataFlowType typeRepr() { result = getErasedRepr(any(Node n).getTypeBound()) }
private DataFlowType typeRepr() { result = getNodeType(_) }
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {
t = typeRepr() and

View File

@@ -24,6 +24,18 @@ abstract class NodeImpl extends Node {
/** Do not call: use `getType()` instead. */
abstract DotNet::Type getTypeImpl();
/** Gets the type of this node used for type pruning. */
cached
DataFlowType getDataFlowType() {
Stages::DataFlowStage::forceCachingInSameStage() and
exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) |
t0 = getCSharpType(this.getType())
or
not exists(getCSharpType(this.getType())) and
t0 instanceof ObjectType
)
}
/** Do not call: use `getControlFlowNode()` instead. */
abstract ControlFlow::Node getControlFlowNodeImpl();
@@ -472,7 +484,7 @@ private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) {
*/
private predicate arrayRead(Expr e1, ArrayRead e2) { e1 = e2.getQualifier() }
Type getCSharpType(DotNet::Type t) {
private Type getCSharpType(DotNet::Type t) {
result = t
or
result.matchesHandle(t)
@@ -1886,7 +1898,7 @@ class LibraryCodeNode extends NodeImpl, TLibraryCodeNode {
override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() }
override DataFlowType getTypeBound() {
override DataFlowType getDataFlowType() {
exists(AccessPath ap |
state = LibraryFlow::TLibraryCodeNodeAfterReadState(ap) and
if sinkAp.length() = 0 and state.isLastReadState() and preservesValue = true
@@ -2049,7 +2061,10 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration
predicate readStep = readStepImpl/3;
/** Gets a string representation of a type returned by `getErasedRepr`. */
/** Gets the type of `n` used for type pruning. */
DataFlowType getNodeType(NodeImpl n) { result = n.getDataFlowType() }
/** Gets a string representation of a `DataFlowType`. */
string ppReprType(DataFlowType t) { result = t.toString() }
private class DataFlowNullType extends DataFlowType {
@@ -2216,6 +2231,3 @@ int accessPathLimit() { result = 3 }
* This predicate is only used for consistency checks.
*/
predicate isImmutableOrUnobservable(Node n) { none() }
pragma[inline]
DataFlowType getErasedRepr(DataFlowType t) { result = t }

View File

@@ -43,18 +43,6 @@ class Node extends TNode {
Stages::DataFlowStage::forceCachingInSameStage() and result = this.(NodeImpl).getTypeImpl()
}
/** INTERNAL: Do not use. Gets an upper bound on the type of this node. */
cached
DataFlowType getTypeBound() {
Stages::DataFlowStage::forceCachingInSameStage() and
exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) |
t0 = getCSharpType(this.getType())
or
not exists(getCSharpType(this.getType())) and
t0 instanceof ObjectType
)
}
/** Gets the enclosing callable of this node. */
cached
final DataFlowCallable getEnclosingCallable() {