mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
C#/C++: Share IR implementation
This commit is contained in:
committed by
AndreiDiaconu1
parent
50ba4d1fda
commit
609ca034c0
@@ -39,42 +39,82 @@
|
||||
"IR Instruction": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll"
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll"
|
||||
],
|
||||
"IR IRBlock": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll"
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll"
|
||||
],
|
||||
"IR IRVariable": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll"
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll"
|
||||
],
|
||||
"IR IRFunction": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll"
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll"
|
||||
],
|
||||
"IR Operand": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll"
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll"
|
||||
],
|
||||
"IR IR": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll"
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll"
|
||||
],
|
||||
"IR IRSanity": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll"
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll"
|
||||
],
|
||||
"IR PrintIR": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll"
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll"
|
||||
],
|
||||
"IR IntegerConstant": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll"
|
||||
],
|
||||
"IR IntegerInteval": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/internal/IntegerInterval.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll"
|
||||
],
|
||||
"IR IntegerPartial": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/internal/IntegerPartial.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll"
|
||||
],
|
||||
"IR Overlap": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/internal/Overlap.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll"
|
||||
],
|
||||
"IR EdgeKind": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll"
|
||||
],
|
||||
"IR MemoryAccessKind": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll"
|
||||
],
|
||||
"IR TempVariableTag": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll"
|
||||
],
|
||||
"IR Opcode": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll"
|
||||
],
|
||||
"C++ IR InstructionImports": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll",
|
||||
@@ -148,5 +188,23 @@
|
||||
"C++ IR PrintDominance": [
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintDominance.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll"
|
||||
],
|
||||
"C# IR InstructionImports": [
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll"
|
||||
],
|
||||
"C# IR IRImports": [
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll"
|
||||
],
|
||||
"C# IR IRBlockImports": [
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll"
|
||||
],
|
||||
"C# IR IRVariableImports": [
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll"
|
||||
],
|
||||
"C# IR OperandImports": [
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll"
|
||||
],
|
||||
"C# IR PrintIRImports": [
|
||||
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ private newtype TOpcode =
|
||||
TDynamicCastToVoid() or
|
||||
TVariableAddress() or
|
||||
TFieldAddress() or
|
||||
TIndexedElementAddress() or
|
||||
TFunctionAddress() or
|
||||
TConstant() or
|
||||
TStringConstant() or
|
||||
@@ -190,6 +191,7 @@ module Opcode {
|
||||
class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { override final string toString() { result = "DynamicCastToVoid" } }
|
||||
class VariableAddress extends Opcode, TVariableAddress { override final string toString() { result = "VariableAddress" } }
|
||||
class FieldAddress extends UnaryOpcode, TFieldAddress { override final string toString() { result = "FieldAddress" } }
|
||||
class IndexedElementAddress extends BinaryOpcode, TIndexedElementAddress { override final string toString() { result = "IndexedElementAddress" } }
|
||||
class FunctionAddress extends Opcode, TFunctionAddress { override final string toString() { result = "FunctionAddress" } }
|
||||
class Constant extends Opcode, TConstant { override final string toString() { result = "Constant" } }
|
||||
class StringConstant extends Opcode, TStringConstant { override final string toString() { result = "StringConstant" } }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import internal.TempVariableTagInternal
|
||||
private import Imports::TempVariableTag
|
||||
|
||||
class TempVariableTag extends TTempVariableTag {
|
||||
string toString() {
|
||||
|
||||
@@ -512,7 +512,7 @@ class Instruction extends Construction::TInstruction {
|
||||
else if getResultType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionResultSize(this)
|
||||
else (
|
||||
result = getResultType().getSize()
|
||||
result = Language::getTypeSize(getResultType())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ class Operand extends TOperand {
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() {
|
||||
result = getType().getSize()
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ class SideEffectOperand extends TypedOperand {
|
||||
if getType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else
|
||||
result = getType().getSize()
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag as TempVariableTag_
|
||||
|
||||
module Imports {
|
||||
module TempVariableTag = TempVariableTag_;
|
||||
}
|
||||
@@ -512,7 +512,7 @@ class Instruction extends Construction::TInstruction {
|
||||
else if getResultType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionResultSize(this)
|
||||
else (
|
||||
result = getResultType().getSize()
|
||||
result = Language::getTypeSize(getResultType())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ class Operand extends TOperand {
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() {
|
||||
result = getType().getSize()
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ class SideEffectOperand extends TypedOperand {
|
||||
if getType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else
|
||||
result = getType().getSize()
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
|
||||
@@ -512,7 +512,7 @@ class Instruction extends Construction::TInstruction {
|
||||
else if getResultType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionResultSize(this)
|
||||
else (
|
||||
result = getResultType().getSize()
|
||||
result = Language::getTypeSize(getResultType())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ class Operand extends TOperand {
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() {
|
||||
result = getType().getSize()
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ class SideEffectOperand extends TypedOperand {
|
||||
if getType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else
|
||||
result = getType().getSize()
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
|
||||
@@ -52,6 +52,10 @@ predicate hasAsmOperandIndex(int operandIndex) {
|
||||
)
|
||||
}
|
||||
|
||||
int getTypeSize(Type type) {
|
||||
result = type.getSize()
|
||||
}
|
||||
|
||||
int getPointerSize() {
|
||||
exists(Cpp::NullPointerType nullptr |
|
||||
result = nullptr.getSize()
|
||||
|
||||
@@ -422,6 +422,9 @@ class ValueType extends ValueOrRefType, @value_type {
|
||||
* (`FloatingPointType`), or a decimal type (`DecimalType`).
|
||||
*/
|
||||
class SimpleType extends ValueType, @simple_type {
|
||||
/** Gets the size of this type, in bytes. */
|
||||
int getSize() { none() }
|
||||
|
||||
/** Gets the minimum integral value of this type, if any. */
|
||||
int minValue() { none() }
|
||||
|
||||
@@ -436,6 +439,8 @@ class SimpleType extends ValueType, @simple_type {
|
||||
*/
|
||||
class BoolType extends SimpleType, @bool_type {
|
||||
override string toStringWithTypes() { result = "bool" }
|
||||
|
||||
override int getSize() { result = 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -444,6 +449,8 @@ class BoolType extends SimpleType, @bool_type {
|
||||
class CharType extends SimpleType, @char_type {
|
||||
override string toStringWithTypes() { result = "char" }
|
||||
|
||||
override int getSize() { result = 2 }
|
||||
|
||||
override int minValue() { result = 0 }
|
||||
|
||||
override int maxValue() { result = 65535 }
|
||||
@@ -481,6 +488,8 @@ class SignedIntegralType extends IntegralType, @signed_integral_type { }
|
||||
class SByteType extends SignedIntegralType, @sbyte_type {
|
||||
override string toStringWithTypes() { result = "sbyte" }
|
||||
|
||||
override int getSize() { result = 1 }
|
||||
|
||||
override int minValue() { result = -128 }
|
||||
|
||||
override int maxValue() { result = 127 }
|
||||
@@ -492,6 +501,8 @@ class SByteType extends SignedIntegralType, @sbyte_type {
|
||||
class ShortType extends SignedIntegralType, @short_type {
|
||||
override string toStringWithTypes() { result = "short" }
|
||||
|
||||
override int getSize() { result = 2 }
|
||||
|
||||
override int minValue() { result = -32768 }
|
||||
|
||||
override int maxValue() { result = 32767 }
|
||||
@@ -503,6 +514,8 @@ class ShortType extends SignedIntegralType, @short_type {
|
||||
class IntType extends SignedIntegralType, @int_type {
|
||||
override string toStringWithTypes() { result = "int" }
|
||||
|
||||
override int getSize() { result = 4 }
|
||||
|
||||
override int minValue() { result = -2147483647 - 1 }
|
||||
|
||||
override int maxValue() { result = 2147483647 }
|
||||
@@ -513,6 +526,8 @@ class IntType extends SignedIntegralType, @int_type {
|
||||
*/
|
||||
class LongType extends SignedIntegralType, @long_type {
|
||||
override string toStringWithTypes() { result = "long" }
|
||||
|
||||
override int getSize() { result = 8 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,6 +536,8 @@ class LongType extends SignedIntegralType, @long_type {
|
||||
class ByteType extends UnsignedIntegralType, @byte_type {
|
||||
override string toStringWithTypes() { result = "byte" }
|
||||
|
||||
override int getSize() { result = 1 }
|
||||
|
||||
override int maxValue() { result = 255 }
|
||||
}
|
||||
|
||||
@@ -530,6 +547,8 @@ class ByteType extends UnsignedIntegralType, @byte_type {
|
||||
class UShortType extends UnsignedIntegralType, @ushort_type {
|
||||
override string toStringWithTypes() { result = "ushort" }
|
||||
|
||||
override int getSize() { result = 2 }
|
||||
|
||||
override int maxValue() { result = 65535 }
|
||||
}
|
||||
|
||||
@@ -538,6 +557,8 @@ class UShortType extends UnsignedIntegralType, @ushort_type {
|
||||
*/
|
||||
class UIntType extends UnsignedIntegralType, @uint_type {
|
||||
override string toStringWithTypes() { result = "uint" }
|
||||
|
||||
override int getSize() { result = 4 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -545,6 +566,8 @@ class UIntType extends UnsignedIntegralType, @uint_type {
|
||||
*/
|
||||
class ULongType extends UnsignedIntegralType, @ulong_type {
|
||||
override string toStringWithTypes() { result = "ulong" }
|
||||
|
||||
override int getSize() { result = 8 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -559,6 +582,8 @@ class FloatingPointType extends SimpleType, @floating_point_type { }
|
||||
*/
|
||||
class FloatType extends FloatingPointType, @float_type {
|
||||
override string toStringWithTypes() { result = "float" }
|
||||
|
||||
override int getSize() { result = 4 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -566,6 +591,8 @@ class FloatType extends FloatingPointType, @float_type {
|
||||
*/
|
||||
class DoubleType extends FloatingPointType, @double_type {
|
||||
override string toStringWithTypes() { result = "double" }
|
||||
|
||||
override int getSize() { result = 8 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -573,6 +600,8 @@ class DoubleType extends FloatingPointType, @double_type {
|
||||
*/
|
||||
class DecimalType extends SimpleType, @decimal_type {
|
||||
override string toStringWithTypes() { result = "decimal" }
|
||||
|
||||
override int getSize() { result = 16 }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
// TODO: Fix the switch
|
||||
import csharp
|
||||
private import internal.EdgeKindInternal
|
||||
|
||||
private newtype TEdgeKind =
|
||||
TGotoEdge() or // Single successor (including fall-through)
|
||||
TTrueEdge() or // 'true' edge of conditional branch
|
||||
TFalseEdge() or // 'false' edge of conditional branch
|
||||
TExceptionEdge() or // Thrown exception
|
||||
TDefaultEdge() or // 'default' label of switch
|
||||
TCaseEdge()
|
||||
TGotoEdge() or // Single successor (including fall-through)
|
||||
TTrueEdge() or // 'true' edge of conditional branch
|
||||
TFalseEdge() or // 'false' edge of conditional branch
|
||||
TExceptionEdge() or // Thrown exception
|
||||
TDefaultEdge() or // 'default' label of switch
|
||||
TCaseEdge(string minValue, string maxValue) { // Case label of switch
|
||||
Language::hasCaseEdge(minValue, maxValue)
|
||||
}
|
||||
|
||||
// TCaseEdge(Expr expr, string condition) { // Case label of switch
|
||||
// exists(CaseStmt caseStmt |
|
||||
// hasCaseEdge(caseStmt, minValue, maxValue)
|
||||
// )
|
||||
// }
|
||||
/**
|
||||
* Represents the kind of an edge in the IR control flow graph. Each
|
||||
* `Instruction` or `IRBlock` has at most one successor of any single
|
||||
@@ -28,99 +24,99 @@ abstract class EdgeKind extends TEdgeKind {
|
||||
* or `IRBlock`.
|
||||
*/
|
||||
class GotoEdge extends EdgeKind, TGotoEdge {
|
||||
final override string toString() { result = "Goto" }
|
||||
override final string toString() {
|
||||
result = "Goto"
|
||||
}
|
||||
}
|
||||
|
||||
GotoEdge gotoEdge() { result = TGotoEdge() }
|
||||
GotoEdge gotoEdge() {
|
||||
result = TGotoEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "true" edge, representing the successor of a conditional branch when the
|
||||
* condition is non-zero.
|
||||
*/
|
||||
class TrueEdge extends EdgeKind, TTrueEdge {
|
||||
final override string toString() { result = "True" }
|
||||
override final string toString() {
|
||||
result = "True"
|
||||
}
|
||||
}
|
||||
|
||||
TrueEdge trueEdge() { result = TTrueEdge() }
|
||||
TrueEdge trueEdge() {
|
||||
result = TTrueEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "false" edge, representing the successor of a conditional branch when the
|
||||
* condition is zero.
|
||||
*/
|
||||
class FalseEdge extends EdgeKind, TFalseEdge {
|
||||
final override string toString() { result = "False" }
|
||||
override final string toString() {
|
||||
result = "False"
|
||||
}
|
||||
}
|
||||
|
||||
FalseEdge falseEdge() { result = TFalseEdge() }
|
||||
FalseEdge falseEdge() {
|
||||
result = TFalseEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* An "exception" edge, representing the successor of an instruction when that
|
||||
* instruction's evaluation throws an exception.
|
||||
*/
|
||||
class ExceptionEdge extends EdgeKind, TExceptionEdge {
|
||||
final override string toString() { result = "Exception" }
|
||||
override final string toString() {
|
||||
result = "Exception"
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionEdge exceptionEdge() { result = TExceptionEdge() }
|
||||
ExceptionEdge exceptionEdge() {
|
||||
result = TExceptionEdge()
|
||||
}
|
||||
|
||||
/**
|
||||
* A "default" edge, representing the successor of a `Switch` instruction when
|
||||
* none of the case values matches the condition value.
|
||||
*/
|
||||
class DefaultEdge extends EdgeKind, TDefaultEdge {
|
||||
final override string toString() { result = "Default" }
|
||||
override final string toString() {
|
||||
result = "Default"
|
||||
}
|
||||
}
|
||||
|
||||
DefaultEdge defaultEdge() { result = TDefaultEdge() }
|
||||
DefaultEdge defaultEdge() {
|
||||
result = TDefaultEdge()
|
||||
}
|
||||
|
||||
///**
|
||||
// * A "case" edge, representing the successor of a `Switch` instruction when the
|
||||
// * the condition value matches a correponding `case` label.
|
||||
// */
|
||||
/**
|
||||
* A "case" edge, representing the successor of a `Switch` instruction when the
|
||||
* the condition value matches a correponding `case` label.
|
||||
*/
|
||||
class CaseEdge extends EdgeKind, TCaseEdge {
|
||||
final override string toString() { result = "CASE" }
|
||||
string minValue;
|
||||
string maxValue;
|
||||
|
||||
CaseEdge() {
|
||||
this = TCaseEdge(minValue, maxValue)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
if minValue = maxValue then
|
||||
result = "Case[" + minValue + "]"
|
||||
else
|
||||
result = "Case[" + minValue + ".." + maxValue + "]"
|
||||
}
|
||||
|
||||
string getMinValue() {
|
||||
result = minValue
|
||||
}
|
||||
|
||||
string getMaxValue() {
|
||||
result = maxValue
|
||||
}
|
||||
}
|
||||
|
||||
CaseEdge caseEdge(string minValue, string maxValue) {
|
||||
result = TCaseEdge(minValue, maxValue)
|
||||
}
|
||||
//class CaseEdge extends EdgeKind, TCaseEdge {
|
||||
// string minValue;
|
||||
// string maxValue;
|
||||
//
|
||||
// CaseEdge() {
|
||||
// this = TCaseEdge(minValue, maxValue)
|
||||
// }
|
||||
//
|
||||
// override final string toString() {
|
||||
// if minValue = maxValue then
|
||||
// result = "Case[" + minValue + "]"
|
||||
// else
|
||||
// result = "Case[" + minValue + ".." + maxValue + "]"
|
||||
// }
|
||||
//
|
||||
// string getMinValue() {
|
||||
// result = minValue
|
||||
// }
|
||||
//
|
||||
// string getMaxValue() {
|
||||
// result = maxValue
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//CaseEdge caseEdge(string minValue, string maxValue) {
|
||||
// result = TCaseEdge(minValue, maxValue)
|
||||
//}
|
||||
//
|
||||
//private predicate hasCaseEdge(CaseStmt caseStmt, string minValue,
|
||||
// string maxValue) {
|
||||
// minValue = caseStmt.getExpr().stripCasts().getValue() and
|
||||
// if exists(caseStmt.getEndExpr()) then
|
||||
// maxValue = caseStmt.getEndExpr().getFullyConverted().getValue()
|
||||
// else
|
||||
// maxValue = minValue
|
||||
//}
|
||||
//
|
||||
//EdgeKind getCaseEdge(SwitchStmt switchStmt) {
|
||||
// exists(CaseEdge edge |
|
||||
// result = edge and
|
||||
// hasCaseEdge(switchStmt, edge.getMinValue(), edge.getMaxValue())
|
||||
// ) or
|
||||
// (switchStmt instanceof DefaultCase and result instanceof DefaultEdge)
|
||||
//}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
private import internal.IRConfigurationInternal
|
||||
|
||||
private newtype TIRConfiguration = MkIRConfiguration()
|
||||
|
||||
/**
|
||||
* The query can extend this class to control which functions have IR generated for them.
|
||||
*/
|
||||
class IRConfiguration extends TIRConfiguration {
|
||||
string toString() {
|
||||
result = "IRConfiguration"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if IR should be created for function `func`. By default, holds for all functions.
|
||||
*/
|
||||
predicate shouldCreateIRForFunction(Language::Function func) {
|
||||
any()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
import csharp
|
||||
|
||||
private newtype TMemoryAccessKind =
|
||||
TIndirectMemoryAccess() or
|
||||
TIndirectMayMemoryAccess() or
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
private newtype TOpcode =
|
||||
TNoOp() or
|
||||
TUninitialized() or
|
||||
TError() or
|
||||
TInitializeParameter() or
|
||||
TInitializeThis() or
|
||||
TEnterFunction() or
|
||||
@@ -148,6 +149,7 @@ abstract class BufferAccessOpcode extends MemoryAccessOpcode {}
|
||||
module Opcode {
|
||||
class NoOp extends Opcode, TNoOp { override final string toString() { result = "NoOp" } }
|
||||
class Uninitialized extends MemoryAccessOpcode, TUninitialized { override final string toString() { result = "Uninitialized" } }
|
||||
class Error extends Opcode, TError { override final string toString() { result = "Error" } }
|
||||
class InitializeParameter extends MemoryAccessOpcode, TInitializeParameter { override final string toString() { result = "InitializeParameter" } }
|
||||
class InitializeThis extends Opcode, TInitializeThis { override final string toString() { result = "InitializeThis" } }
|
||||
class EnterFunction extends Opcode, TEnterFunction { override final string toString() { result = "EnterFunction" } }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.ir.internal.TempVariableTag
|
||||
private import internal.TempVariableTagInternal
|
||||
private import Imports::TempVariableTag
|
||||
|
||||
class TempVariableTag extends TTempVariableTag {
|
||||
string toString() {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
@@ -1,12 +1,4 @@
|
||||
import csharp
|
||||
|
||||
private int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(MethodCall call |
|
||||
exists(call.getArgument(argIndex))
|
||||
)
|
||||
)
|
||||
}
|
||||
private import OperandTagInternal
|
||||
|
||||
private newtype TOperandTag =
|
||||
TAddressOperand() or
|
||||
@@ -22,10 +14,13 @@ private newtype TOperandTag =
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..getMaxCallArgIndex()]
|
||||
Language::hasPositionalArgIndex(argIndex)
|
||||
} or
|
||||
TChiTotalOperand() or
|
||||
TChiPartialOperand()
|
||||
TChiPartialOperand() or
|
||||
TAsmOperand(int index) {
|
||||
Language::hasAsmOperandIndex(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
@@ -359,3 +354,27 @@ class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand {
|
||||
ChiPartialOperandTag chiPartialOperand() {
|
||||
result = TChiPartialOperand()
|
||||
}
|
||||
|
||||
class AsmOperandTag extends RegisterOperandTag, TAsmOperand {
|
||||
int index;
|
||||
|
||||
AsmOperandTag() {
|
||||
this = TAsmOperand(index)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "AsmOperand(" + index + ")"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 15 + index
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = index.toString() + ":"
|
||||
}
|
||||
}
|
||||
|
||||
AsmOperandTag asmOperand(int index) {
|
||||
result = TAsmOperand(index)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
@@ -0,0 +1,12 @@
|
||||
private import TIRVariableInternal
|
||||
private import Imports::TempVariableTag
|
||||
|
||||
newtype TIRVariable =
|
||||
TIRUserVariable(Language::Variable var, Language::Type type,
|
||||
Language::Function func) {
|
||||
Construction::hasUserVariable(func, var, type)
|
||||
} or
|
||||
TIRTempVariable(Language::Function func, Language::AST ast, TempVariableTag tag,
|
||||
Language::Type type) {
|
||||
Construction::hasTempVariable(func, ast, tag, type)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as Construction
|
||||
private import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag_
|
||||
|
||||
module Imports {
|
||||
module TempVariableTag = TempVariableTag_;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
private import semmle.code.csharp.ir.internal.TempVariableTag as TempVariableTag_
|
||||
|
||||
module Imports {
|
||||
module TempVariableTag = TempVariableTag_;
|
||||
}
|
||||
@@ -3,8 +3,9 @@ import Instruction
|
||||
import IRBlock
|
||||
import IRVariable
|
||||
import Operand
|
||||
import semmle.code.csharp.ir.implementation.EdgeKind
|
||||
import semmle.code.csharp.ir.implementation.MemoryAccessKind
|
||||
private import internal.IRImports as Imports
|
||||
import Imports::EdgeKind
|
||||
import Imports::MemoryAccessKind
|
||||
|
||||
private newtype TIRPropertyProvider = MkIRPropertyProvider()
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import semmle.code.csharp.ir.implementation.EdgeKind
|
||||
private import internal.IRBlockImports as Imports
|
||||
import Imports::EdgeKind
|
||||
private import Cached
|
||||
|
||||
/**
|
||||
@@ -19,7 +20,7 @@ class IRBlockBase extends TIRBlock {
|
||||
result = getFirstInstruction(this).toString()
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
final Language::Location getLocation() {
|
||||
result = getFirstInstruction().getLocation()
|
||||
}
|
||||
|
||||
@@ -67,7 +68,7 @@ class IRBlockBase extends TIRBlock {
|
||||
result = getFirstInstruction(this).getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
final Callable getEnclosingFunction() {
|
||||
final Language::Function getEnclosingFunction() {
|
||||
result = getFirstInstruction(this).getEnclosingFunction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,37 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import csharp
|
||||
|
||||
private newtype TIRFunction =
|
||||
MkIRFunction(Callable callable) {
|
||||
Construction::functionHasIR(callable)
|
||||
MkIRFunction(Language::Function func) {
|
||||
Construction::functionHasIR(func)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR for a function.
|
||||
*/
|
||||
class IRFunction extends TIRFunction {
|
||||
Callable callable;
|
||||
Language::Function func;
|
||||
|
||||
IRFunction() {
|
||||
this = MkIRFunction(callable)
|
||||
this = MkIRFunction(func)
|
||||
}
|
||||
|
||||
final string toString() {
|
||||
result = "IR: " + callable.toString()
|
||||
result = "IR: " + func.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function whose IR is represented.
|
||||
*/
|
||||
final Callable getFunction() {
|
||||
result = callable
|
||||
final Language::Function getFunction() {
|
||||
result = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the function.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
result = callable.getLocation()
|
||||
final Language::Location getLocation() {
|
||||
result = func.getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
private import internal.IRInternal
|
||||
import IRFunction
|
||||
import csharp
|
||||
import semmle.code.csharp.ir.implementation.TempVariableTag
|
||||
private import semmle.code.csharp.ir.internal.IRUtilities
|
||||
private import semmle.code.csharp.ir.internal.TempVariableTag
|
||||
private import semmle.code.csharp.ir.internal.TIRVariable
|
||||
private import semmle.code.csharp.ir.Util
|
||||
private import internal.IRVariableImports as Imports
|
||||
import Imports::TempVariableTag
|
||||
private import Imports::IRUtilities
|
||||
private import Imports::TTempVariableTag
|
||||
private import Imports::TIRVariable
|
||||
|
||||
IRUserVariable getIRUserVariable(Callable callable, Variable var) {
|
||||
IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) {
|
||||
result.getVariable() = var and
|
||||
result.getEnclosingFunction() = callable
|
||||
result.getEnclosingFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -18,20 +17,20 @@ IRUserVariable getIRUserVariable(Callable callable, Variable var) {
|
||||
* generated by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
abstract class IRVariable extends TIRVariable {
|
||||
Callable callable;
|
||||
Language::Function func;
|
||||
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
abstract Type getType();
|
||||
abstract Language::Type getType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
abstract Locatable getAST();
|
||||
abstract Language::AST getAST();
|
||||
|
||||
/**
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
@@ -42,7 +41,7 @@ abstract class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
final Language::Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
|
||||
@@ -50,43 +49,48 @@ abstract class IRVariable extends TIRVariable {
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result.getFunction() = callable
|
||||
result.getFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
*/
|
||||
final Callable getEnclosingFunction() {
|
||||
result = callable
|
||||
final Language::Function getEnclosingFunction() {
|
||||
result = func
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
abstract class IRUserVariable extends IRVariable {
|
||||
Variable var;
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
Language::Type type;
|
||||
|
||||
IRUserVariable() {
|
||||
this = TIRUserVariable(var, type, func)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = var.toString()
|
||||
result = getVariable().toString()
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
result = getVariableType(var)
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
override final Language::AST getAST() {
|
||||
result = var
|
||||
}
|
||||
|
||||
override final string getUniqueId() {
|
||||
result = var.toString() + " " + var.getLocation().toString()
|
||||
result = getVariable().toString() + " " + getVariable().getLocation().toString()
|
||||
}
|
||||
|
||||
override final Language::Type getType() {
|
||||
result = type
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original user-declared variable.
|
||||
*/
|
||||
final Variable getVariable() {
|
||||
Language::Variable getVariable() {
|
||||
result = var
|
||||
}
|
||||
}
|
||||
@@ -99,45 +103,49 @@ abstract class IRUserVariable extends IRVariable {
|
||||
abstract class IRAutomaticVariable extends IRVariable {
|
||||
}
|
||||
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable,
|
||||
TIRAutomaticUserVariable {
|
||||
LocalScopeVariable localVar;
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
IRAutomaticUserVariable() {
|
||||
this = TIRAutomaticUserVariable(localVar, callable) and
|
||||
var = localVar
|
||||
Language::isVariableAutomatic(var)
|
||||
}
|
||||
|
||||
final LocalScopeVariable getLocalVariable() {
|
||||
result = localVar
|
||||
final override Language::AutomaticVariable getVariable() {
|
||||
result = var
|
||||
}
|
||||
}
|
||||
|
||||
class IRStaticUserVariable extends IRUserVariable, TIRStaticUserVariable {
|
||||
class IRStaticUserVariable extends IRUserVariable {
|
||||
override Language::StaticVariable var;
|
||||
|
||||
IRStaticUserVariable() {
|
||||
this = TIRStaticUserVariable(var, callable)
|
||||
not Language::isVariableAutomatic(var)
|
||||
}
|
||||
|
||||
final override Language::StaticVariable getVariable() {
|
||||
result = var
|
||||
}
|
||||
}
|
||||
|
||||
IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) {
|
||||
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
|
||||
result.getAST() = ast and
|
||||
result.getTag() = tag
|
||||
}
|
||||
|
||||
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
Locatable ast;
|
||||
Language::AST ast;
|
||||
TempVariableTag tag;
|
||||
Type type;
|
||||
Language::Type type;
|
||||
|
||||
IRTempVariable() {
|
||||
this = TIRTempVariable(callable, ast, tag, type)
|
||||
this = TIRTempVariable(func, ast, tag, type)
|
||||
}
|
||||
|
||||
override final Type getType() {
|
||||
override final Language::Type getType() {
|
||||
result = type
|
||||
}
|
||||
|
||||
override final Locatable getAST() {
|
||||
override final Language::AST getAST() {
|
||||
result = ast
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,11 @@ import IRFunction
|
||||
import IRBlock
|
||||
import IRVariable
|
||||
import Operand
|
||||
import csharp
|
||||
import semmle.code.csharp.ir.implementation.EdgeKind
|
||||
import semmle.code.csharp.ir.implementation.MemoryAccessKind
|
||||
import semmle.code.csharp.ir.implementation.Opcode
|
||||
private import semmle.code.csharp.ir.implementation.Opcode
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.Util
|
||||
private import internal.InstructionImports as Imports
|
||||
import Imports::EdgeKind
|
||||
import Imports::MemoryAccessKind
|
||||
import Imports::Opcode
|
||||
private import Imports::OperandTag
|
||||
|
||||
module InstructionSanity {
|
||||
/**
|
||||
@@ -51,7 +49,6 @@ module InstructionSanity {
|
||||
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
|
||||
*/
|
||||
query predicate missingOperand(Instruction instr, string message, IRFunction func, string funcText) {
|
||||
instr.getAST().fromSource() and
|
||||
exists(OperandTag tag |
|
||||
expectsOperand(instr, tag) and
|
||||
not exists(NonPhiOperand operand |
|
||||
@@ -61,7 +58,7 @@ module InstructionSanity {
|
||||
message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" +
|
||||
tag.toString() + "' in function '$@'." and
|
||||
func = instr.getEnclosingIRFunction() and
|
||||
funcText = func.getFunction().getName()
|
||||
funcText = Language::getIdentityString(func.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -69,20 +66,19 @@ module InstructionSanity {
|
||||
* Holds if instruction `instr` has an unexpected operand with tag `tag`.
|
||||
*/
|
||||
query predicate unexpectedOperand(Instruction instr, OperandTag tag) {
|
||||
instr.getAST().fromSource() and
|
||||
exists(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag) and
|
||||
not expectsOperand(instr, tag) and
|
||||
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
|
||||
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
|
||||
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag) and
|
||||
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if instruction `instr` has multiple operands with tag `tag`.
|
||||
*/
|
||||
query predicate duplicateOperand(Instruction instr, OperandTag tag) {
|
||||
instr.getAST().fromSource() and
|
||||
strictcount(NonPhiOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
operand.getOperandTag() = tag
|
||||
@@ -95,7 +91,6 @@ module InstructionSanity {
|
||||
* the predecessor block `pred`.
|
||||
*/
|
||||
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
|
||||
instr.getAST().fromSource() and pred.getEnclosingFunction().fromSource() and
|
||||
pred = instr.getBlock().getAPredecessor() and
|
||||
not exists(PhiInputOperand operand |
|
||||
operand = instr.getAnOperand() and
|
||||
@@ -104,10 +99,10 @@ module InstructionSanity {
|
||||
}
|
||||
|
||||
query predicate missingOperandType(Operand operand, string message) {
|
||||
exists(Callable callable |
|
||||
exists(Language::Function func |
|
||||
not exists(operand.getType()) and
|
||||
callable = operand.getUseInstruction().getEnclosingFunction() and
|
||||
message = "Operand missing type in function '" + callable.getName() + "'."
|
||||
func = operand.getUse().getEnclosingFunction() and
|
||||
message = "Operand missing type in function '" + Language::getIdentityString(func) + "'."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -115,7 +110,6 @@ module InstructionSanity {
|
||||
* Holds if an instruction, other than `ExitFunction`, has no successors.
|
||||
*/
|
||||
query predicate instructionWithoutSuccessor(Instruction instr) {
|
||||
instr.getAST().fromSource() and
|
||||
not exists(instr.getASuccessor()) and
|
||||
not instr instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
@@ -130,7 +124,6 @@ module InstructionSanity {
|
||||
query predicate ambiguousSuccessors(
|
||||
Instruction source, EdgeKind kind, int n, Instruction target
|
||||
) {
|
||||
source.getAST().fromSource() and target.getAST().fromSource() and
|
||||
n = strictcount(Instruction t | source.getSuccessor(kind) = t) and
|
||||
n > 1 and
|
||||
source.getSuccessor(kind) = target
|
||||
@@ -140,15 +133,13 @@ module InstructionSanity {
|
||||
* Holds if `instr` in `f` is part of a loop even though the AST of `f`
|
||||
* contains no element that can cause loops.
|
||||
*/
|
||||
query predicate unexplainedLoop(Callable f, Instruction instr) {
|
||||
instr.getAST().fromSource() and f.fromSource() and
|
||||
query predicate unexplainedLoop(Language::Function f, Instruction instr) {
|
||||
exists(IRBlock block |
|
||||
instr.getBlock() = block and
|
||||
block.getEnclosingFunction() = f and
|
||||
block.getASuccessor+() = block
|
||||
) and
|
||||
not exists(LoopStmt l | l.getEnclosingCallable() = f) and
|
||||
not exists(GotoStmt s | s.getEnclosingCallable() = f)
|
||||
not Language::hasPotentialLoop(f)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,7 +147,6 @@ module InstructionSanity {
|
||||
* predecessors.
|
||||
*/
|
||||
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
|
||||
instr.getAST().fromSource() and
|
||||
count(instr.getBlock().getAPredecessor()) < 2
|
||||
}
|
||||
|
||||
@@ -165,9 +155,8 @@ module InstructionSanity {
|
||||
* a different function.
|
||||
*/
|
||||
query predicate operandAcrossFunctions(Operand operand, Instruction instr, Instruction defInstr) {
|
||||
instr.getAST().fromSource() and defInstr.getAST().fromSource() and
|
||||
operand.getUseInstruction() = instr and
|
||||
operand.getDefinitionInstruction() = defInstr and
|
||||
operand.getUse() = instr and
|
||||
operand.getAnyDef() = defInstr and
|
||||
instr.getEnclosingIRFunction() != defInstr.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
@@ -175,13 +164,11 @@ module InstructionSanity {
|
||||
* Holds if instruction `instr` is not in exactly one block.
|
||||
*/
|
||||
query predicate instructionWithoutUniqueBlock(Instruction instr, int blockCount) {
|
||||
instr.getAST().fromSource() and
|
||||
blockCount = count(instr.getBlock()) and
|
||||
blockCount != 1
|
||||
}
|
||||
|
||||
private predicate forwardEdge(IRBlock b1, IRBlock b2) {
|
||||
b1.getEnclosingFunction().fromSource() and b2.getEnclosingFunction().fromSource() and
|
||||
b1.getASuccessor() = b2 and
|
||||
not b1.getBackEdgeSuccessor(_) = b2
|
||||
}
|
||||
@@ -192,7 +179,6 @@ module InstructionSanity {
|
||||
* This check ensures we don't have too _few_ back edges.
|
||||
*/
|
||||
query predicate containsLoopOfForwardEdges(IRFunction f) {
|
||||
f.getFunction().fromSource() and
|
||||
exists(IRBlock block |
|
||||
forwardEdge+(block, block) and
|
||||
block.getEnclosingIRFunction() = f
|
||||
@@ -208,12 +194,11 @@ module InstructionSanity {
|
||||
* This check ensures we don't have too _many_ back edges.
|
||||
*/
|
||||
query predicate lostReachability(IRBlock block) {
|
||||
block.getEnclosingFunction().fromSource() and
|
||||
exists(IRFunction f, IRBlock entry |
|
||||
entry = f.getEntryBlock() and
|
||||
entry.getASuccessor+() = block and
|
||||
not forwardEdge+(entry, block) and
|
||||
not exists(GotoStmt s | s.getEnclosingCallable() = f.getFunction())
|
||||
not Language::hasGoto(f.getFunction())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -221,8 +206,7 @@ module InstructionSanity {
|
||||
* Holds if the number of back edges differs between the `Instruction` graph
|
||||
* and the `IRBlock` graph.
|
||||
*/
|
||||
query predicate backEdgeCountMismatch(Callable f, int fromInstr, int fromBlock) {
|
||||
f.fromSource() and
|
||||
query predicate backEdgeCountMismatch(Language::Function f, int fromInstr, int fromBlock) {
|
||||
fromInstr = count(Instruction i1, Instruction i2 |
|
||||
i1.getEnclosingFunction() = f and i1.getBackEdgeSuccessor(_) = i2
|
||||
) and
|
||||
@@ -279,7 +263,7 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
private string getResultPrefix() {
|
||||
if getResultType() instanceof VoidType then
|
||||
if getResultType() instanceof Language::VoidType then
|
||||
result = "v"
|
||||
else if hasMemoryResult() then
|
||||
if isResultModeled() then
|
||||
@@ -316,20 +300,19 @@ class Instruction extends Construction::TInstruction {
|
||||
|
||||
bindingset[type]
|
||||
private string getValueCategoryString(string type) {
|
||||
if isLValue() then
|
||||
result = "lval<" + type + ">"
|
||||
if isGLValue() then
|
||||
result = "glval<" + type + ">"
|
||||
else
|
||||
result = type
|
||||
}
|
||||
|
||||
// TODO: Memory model in C#?
|
||||
string getResultTypeString() {
|
||||
exists(string valcat |
|
||||
valcat = getValueCategoryString(getResultType().toString()) and
|
||||
if (getResultType() instanceof UnknownType and
|
||||
not isLValue())/* and
|
||||
exists(getResultSize()))*/ then (
|
||||
result = valcat + "[" + /*getResultSize().toString()*/8.toString() + "]"
|
||||
if (getResultType() instanceof Language::UnknownType and
|
||||
not isGLValue() and
|
||||
exists(getResultSize())) then (
|
||||
result = valcat + "[" + getResultSize().toString() + "]"
|
||||
)
|
||||
else
|
||||
result = valcat
|
||||
@@ -393,7 +376,7 @@ class Instruction extends Construction::TInstruction {
|
||||
/**
|
||||
* Gets the function that contains this instruction.
|
||||
*/
|
||||
final Callable getEnclosingFunction() {
|
||||
final Language::Function getEnclosingFunction() {
|
||||
result = getEnclosingIRFunction().getFunction()
|
||||
}
|
||||
|
||||
@@ -407,28 +390,28 @@ class Instruction extends Construction::TInstruction {
|
||||
/**
|
||||
* Gets the AST that caused this instruction to be generated.
|
||||
*/
|
||||
final Locatable getAST() {
|
||||
final Language::AST getAST() {
|
||||
result = Construction::getInstructionAST(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the source code for this instruction.
|
||||
*/
|
||||
final Location getLocation() {
|
||||
final Language::Location getLocation() {
|
||||
result = getAST().getLocation()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getConvertedResultExpression() {
|
||||
final Language::Expr getConvertedResultExpression() {
|
||||
result = Construction::getInstructionConvertedResultExpression(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unconverted `Expr` whose result is computed by this instruction, if any.
|
||||
*/
|
||||
final Expr getUnconvertedResultExpression() {
|
||||
final Language::Expr getUnconvertedResultExpression() {
|
||||
result = Construction::getInstructionUnconvertedResultExpression(this)
|
||||
}
|
||||
|
||||
@@ -439,7 +422,7 @@ class Instruction extends Construction::TInstruction {
|
||||
* If `isGLValue()` holds, then the result type of this instruction should be
|
||||
* thought of as "pointer to `getResultType()`".
|
||||
*/
|
||||
final Type getResultType() {
|
||||
final Language::Type getResultType() {
|
||||
Construction::instructionHasType(this, result, _)
|
||||
}
|
||||
|
||||
@@ -461,31 +444,28 @@ class Instruction extends Construction::TInstruction {
|
||||
* result of the `Load` instruction is a prvalue of type `int`, representing
|
||||
* the integer value loaded from variable `x`.
|
||||
*/
|
||||
final predicate isLValue() {
|
||||
final predicate isGLValue() {
|
||||
Construction::instructionHasType(this, _, true)
|
||||
}
|
||||
|
||||
// TODO: Memory model in C#
|
||||
// /**
|
||||
// * Gets the size of the result produced by this instruction, in bytes. If the
|
||||
// * result does not have a known constant size, this predicate does not hold.
|
||||
// *
|
||||
// * If `this.isGLValue()` holds for this instruction, the value of
|
||||
// * `getResultSize()` will always be the size of a pointer.
|
||||
// */
|
||||
// final int getResultSize() {
|
||||
// if isGLValue() then (
|
||||
// // a glvalue is always pointer-sized.
|
||||
// exists(NullPointerType nullptr |
|
||||
// result = nullptr.getSize()
|
||||
// )
|
||||
// )
|
||||
// else if getResultType() instanceof UnknownType then
|
||||
// result = Construction::getInstructionResultSize(this)
|
||||
// else (
|
||||
// result = getResultType().getSize()
|
||||
// )
|
||||
// }
|
||||
/**
|
||||
* Gets the size of the result produced by this instruction, in bytes. If the
|
||||
* result does not have a known constant size, this predicate does not hold.
|
||||
*
|
||||
* If `this.isGLValue()` holds for this instruction, the value of
|
||||
* `getResultSize()` will always be the size of a pointer.
|
||||
*/
|
||||
final int getResultSize() {
|
||||
if isGLValue() then (
|
||||
// a glvalue is always pointer-sized.
|
||||
result = Language::getPointerSize()
|
||||
)
|
||||
else if getResultType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionResultSize(this)
|
||||
else (
|
||||
result = Language::getTypeSize(getResultType())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the opcode that specifies the operation performed by this instruction.
|
||||
@@ -495,17 +475,18 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all direct uses of the result of this instruction.
|
||||
* Gets all direct uses of the result of this instruction. The result can be
|
||||
* an `Operand` for which `isDefinitionInexact` holds.
|
||||
*/
|
||||
final Operand getAUse() {
|
||||
result.getDefinitionInstruction() = this
|
||||
result.getAnyDef() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all of this instruction's operands.
|
||||
*/
|
||||
final Operand getAnOperand() {
|
||||
result.getUseInstruction() = this
|
||||
result.getUse() = this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -524,13 +505,22 @@ class Instruction extends Construction::TInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the operand that holds the memory address to which the instruction stores its
|
||||
* Gets the operand that holds the memory address to which this instruction stores its
|
||||
* result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()`
|
||||
* is `r1`.
|
||||
*/
|
||||
final AddressOperand getResultAddressOperand() {
|
||||
getResultMemoryAccess().usesAddressOperand() and
|
||||
result.getUseInstruction() = this
|
||||
result.getUse() = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction that holds the exact memory address to which this instruction stores its
|
||||
* result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()`
|
||||
* is the instruction that defines `r1`.
|
||||
*/
|
||||
final Instruction getResultAddress() {
|
||||
result = getResultAddressOperand().getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -621,7 +611,7 @@ class VariableInstruction extends Instruction {
|
||||
}
|
||||
|
||||
class FieldInstruction extends Instruction {
|
||||
Field field;
|
||||
Language::Field field;
|
||||
|
||||
FieldInstruction() {
|
||||
field = Construction::getInstructionField(this)
|
||||
@@ -631,13 +621,13 @@ class FieldInstruction extends Instruction {
|
||||
result = field.toString()
|
||||
}
|
||||
|
||||
final Field getField() {
|
||||
final Language::Field getField() {
|
||||
result = field
|
||||
}
|
||||
}
|
||||
|
||||
class FunctionInstruction extends Instruction {
|
||||
Callable funcSymbol;
|
||||
Language::Function funcSymbol;
|
||||
|
||||
FunctionInstruction() {
|
||||
funcSymbol = Construction::getInstructionFunction(this)
|
||||
@@ -647,7 +637,7 @@ class FunctionInstruction extends Instruction {
|
||||
result = funcSymbol.toString()
|
||||
}
|
||||
|
||||
final Callable getFunctionSymbol() {
|
||||
final Language::Function getFunctionSymbol() {
|
||||
result = funcSymbol
|
||||
}
|
||||
}
|
||||
@@ -685,7 +675,7 @@ class InitializeParameterInstruction extends VariableInstruction {
|
||||
getOpcode() instanceof Opcode::InitializeParameter
|
||||
}
|
||||
|
||||
final Parameter getParameter() {
|
||||
final Language::Parameter getParameter() {
|
||||
result = var.(IRUserVariable).getVariable()
|
||||
}
|
||||
|
||||
@@ -713,7 +703,23 @@ class FieldAddressInstruction extends FieldInstruction {
|
||||
}
|
||||
|
||||
final Instruction getObjectAddress() {
|
||||
result = getObjectAddressOperand().getDefinitionInstruction()
|
||||
result = getObjectAddressOperand().getDef()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that produces a well-defined but unknown result and has
|
||||
* unknown side effects, including side effects that are not conservatively
|
||||
* modeled in the SSA graph.
|
||||
*
|
||||
* This type of instruction appears when there is an `ErrorExpr` in the AST,
|
||||
* meaning that the extractor could not understand the expression and therefore
|
||||
* produced a partial AST. Queries that give alerts when some action is _not_
|
||||
* taken may want to ignore any function that contains an `ErrorInstruction`.
|
||||
*/
|
||||
class ErrorInstruction extends Instruction {
|
||||
ErrorInstruction() {
|
||||
getOpcode() instanceof Opcode::Error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -727,9 +733,9 @@ class UninitializedInstruction extends VariableInstruction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `LocalVariable` that is uninitialized.
|
||||
* Gets the variable that is uninitialized.
|
||||
*/
|
||||
final LocalVariable getLocalVariable() {
|
||||
final Language::Variable getLocalVariable() {
|
||||
result = var.(IRUserVariable).getVariable()
|
||||
}
|
||||
}
|
||||
@@ -762,7 +768,7 @@ class ReturnValueInstruction extends ReturnInstruction {
|
||||
}
|
||||
|
||||
final Instruction getReturnValue() {
|
||||
result = getReturnValueOperand().getDefinitionInstruction()
|
||||
result = getReturnValueOperand().getDef()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -776,7 +782,7 @@ class CopyInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getSourceValue() {
|
||||
result = getSourceValueOperand().getDefinitionInstruction()
|
||||
result = getSourceValueOperand().getDef()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -800,7 +806,7 @@ class LoadInstruction extends CopyInstruction {
|
||||
}
|
||||
|
||||
final Instruction getSourceAddress() {
|
||||
result = getSourceAddressOperand().getDefinitionInstruction()
|
||||
result = getSourceAddressOperand().getDef()
|
||||
}
|
||||
|
||||
override final LoadOperand getSourceValueOperand() {
|
||||
@@ -822,7 +828,7 @@ class StoreInstruction extends CopyInstruction {
|
||||
}
|
||||
|
||||
final Instruction getDestinationAddress() {
|
||||
result = getDestinationAddressOperand().getDefinitionInstruction()
|
||||
result = getDestinationAddressOperand().getDef()
|
||||
}
|
||||
|
||||
override final StoreValueOperand getSourceValueOperand() {
|
||||
@@ -840,7 +846,7 @@ class ConditionalBranchInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getCondition() {
|
||||
result = getConditionOperand().getDefinitionInstruction()
|
||||
result = getConditionOperand().getDef()
|
||||
}
|
||||
|
||||
final Instruction getTrueSuccessor() {
|
||||
@@ -866,28 +872,28 @@ class ConstantInstruction extends ConstantValueInstruction {
|
||||
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() {
|
||||
getResultType() instanceof IntegralType
|
||||
getResultType() instanceof Language::IntegralType
|
||||
}
|
||||
}
|
||||
|
||||
class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() {
|
||||
getResultType() instanceof FloatingPointType
|
||||
getResultType() instanceof Language::FloatingPointType
|
||||
}
|
||||
}
|
||||
|
||||
class StringConstantInstruction extends Instruction {
|
||||
StringLiteral value;
|
||||
Language::StringLiteral value;
|
||||
|
||||
StringConstantInstruction() {
|
||||
value = Construction::getInstructionStringLiteral(this)
|
||||
}
|
||||
|
||||
override final string getImmediateString() {
|
||||
result = value.toString().replaceAll("\n", " ").replaceAll("\r", "").replaceAll("\t", " ")
|
||||
result = Language::getStringLiteralText(value)
|
||||
}
|
||||
|
||||
final StringLiteral getValue() {
|
||||
final Language::StringLiteral getValue() {
|
||||
result = value
|
||||
}
|
||||
}
|
||||
@@ -906,11 +912,11 @@ class BinaryInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getLeft() {
|
||||
result = getLeftOperand().getDefinitionInstruction()
|
||||
result = getLeftOperand().getDef()
|
||||
}
|
||||
|
||||
final Instruction getRight() {
|
||||
result = getRightOperand().getDefinitionInstruction()
|
||||
result = getRightOperand().getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1060,7 +1066,7 @@ class UnaryInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getUnary() {
|
||||
result = getUnaryOperand().getDefinitionInstruction()
|
||||
result = getUnaryOperand().getDef()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1075,8 +1081,8 @@ class ConvertInstruction extends UnaryInstruction {
|
||||
* related by inheritance.
|
||||
*/
|
||||
class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
Class baseClass;
|
||||
Class derivedClass;
|
||||
Language::Class baseClass;
|
||||
Language::Class derivedClass;
|
||||
|
||||
InheritanceConversionInstruction() {
|
||||
Construction::getInstructionInheritance(this, baseClass, derivedClass)
|
||||
@@ -1086,29 +1092,28 @@ class InheritanceConversionInstruction extends UnaryInstruction {
|
||||
result = derivedClass.toString() + " : " + baseClass.toString()
|
||||
}
|
||||
|
||||
// TODO: WHAT IS THE EQUIV IN C#
|
||||
// /**
|
||||
// * Gets the `ClassDerivation` for the inheritance relationship between
|
||||
// * the base and derived classes. This predicate does not hold if the
|
||||
// * conversion is to an indirect virtual base class.
|
||||
// */
|
||||
// final ClassDerivation getDerivation() {
|
||||
// result.getBaseClass() = baseClass and result.getDerivedClass() = derivedClass
|
||||
// }
|
||||
/**
|
||||
* Gets the `ClassDerivation` for the inheritance relationship between
|
||||
* the base and derived classes. This predicate does not hold if the
|
||||
* conversion is to an indirect virtual base class.
|
||||
*/
|
||||
final Language::ClassDerivation getDerivation() {
|
||||
result.getBaseClass() = baseClass and result.getDerivedClass() = derivedClass
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base class of the conversion. This will be either a direct
|
||||
* base class of the derived class, or a virtual base class of the
|
||||
* derived class.
|
||||
*/
|
||||
final Class getBaseClass() {
|
||||
final Language::Class getBaseClass() {
|
||||
result = baseClass
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the derived class of the conversion.
|
||||
*/
|
||||
final Class getDerivedClass() {
|
||||
final Language::Class getDerivedClass() {
|
||||
result = derivedClass
|
||||
}
|
||||
}
|
||||
@@ -1291,7 +1296,7 @@ class SwitchInstruction extends Instruction {
|
||||
}
|
||||
|
||||
final Instruction getExpression() {
|
||||
result = getExpressionOperand().getDefinitionInstruction()
|
||||
result = getExpressionOperand().getDef()
|
||||
}
|
||||
|
||||
final Instruction getACaseSuccessor() {
|
||||
@@ -1326,7 +1331,7 @@ class CallInstruction extends Instruction {
|
||||
* function pointer.
|
||||
*/
|
||||
final Instruction getCallTarget() {
|
||||
result = getCallTargetOperand().getDefinitionInstruction()
|
||||
result = getCallTargetOperand().getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1339,7 +1344,7 @@ class CallInstruction extends Instruction {
|
||||
/**
|
||||
* Gets the `Function` that the call targets, if this is statically known.
|
||||
*/
|
||||
final Callable getStaticCallTarget() {
|
||||
final Language::Function getStaticCallTarget() {
|
||||
result = getCallTarget().(FunctionInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
@@ -1347,7 +1352,7 @@ class CallInstruction extends Instruction {
|
||||
* Gets all of the arguments of the call, including the `this` pointer, if any.
|
||||
*/
|
||||
final Instruction getAnArgument() {
|
||||
result = getAnArgumentOperand().getDefinitionInstruction()
|
||||
result = getAnArgumentOperand().getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1361,7 +1366,7 @@ class CallInstruction extends Instruction {
|
||||
* Gets the `this` pointer argument of the call, if any.
|
||||
*/
|
||||
final Instruction getThisArgument() {
|
||||
result = getThisArgumentOperand().getDefinitionInstruction()
|
||||
result = getThisArgumentOperand().getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1376,7 +1381,7 @@ class CallInstruction extends Instruction {
|
||||
* Gets the argument at the specified index.
|
||||
*/
|
||||
final Instruction getPositionalArgument(int index) {
|
||||
result = getPositionalArgumentOperand(index).getDefinitionInstruction()
|
||||
result = getPositionalArgumentOperand(index).getDef()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1532,7 +1537,7 @@ class ThrowValueInstruction extends ThrowInstruction {
|
||||
* Gets the address of the exception thrown by this instruction.
|
||||
*/
|
||||
final Instruction getExceptionAddress() {
|
||||
result = getExceptionAddressOperand().getDefinitionInstruction()
|
||||
result = getExceptionAddressOperand().getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1546,7 +1551,7 @@ class ThrowValueInstruction extends ThrowInstruction {
|
||||
* Gets the exception thrown by this instruction.
|
||||
*/
|
||||
final Instruction getException() {
|
||||
result = getExceptionOperand().getDefinitionInstruction()
|
||||
result = getExceptionOperand().getDef()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1581,7 +1586,7 @@ class CatchInstruction extends Instruction {
|
||||
* An instruction that catches an exception of a specific type.
|
||||
*/
|
||||
class CatchByTypeInstruction extends CatchInstruction {
|
||||
Type exceptionType;
|
||||
Language::Type exceptionType;
|
||||
|
||||
CatchByTypeInstruction() {
|
||||
getOpcode() instanceof Opcode::CatchByType and
|
||||
@@ -1595,7 +1600,7 @@ class CatchByTypeInstruction extends CatchInstruction {
|
||||
/**
|
||||
* Gets the type of exception to be caught.
|
||||
*/
|
||||
final Type getExceptionType() {
|
||||
final Language::Type getExceptionType() {
|
||||
result = exceptionType
|
||||
}
|
||||
}
|
||||
@@ -1676,7 +1681,7 @@ class PhiInstruction extends Instruction {
|
||||
*/
|
||||
pragma[noinline]
|
||||
final Instruction getAnInput() {
|
||||
result = this.getAnInputOperand().getDefinitionInstruction()
|
||||
result = this.getAnInputOperand().getDef()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1744,7 +1749,7 @@ class ChiInstruction extends Instruction {
|
||||
* memory write.
|
||||
*/
|
||||
final Instruction getTotal() {
|
||||
result = getTotalOperand().getDefinitionInstruction()
|
||||
result = getTotalOperand().getDef()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1758,7 +1763,7 @@ class ChiInstruction extends Instruction {
|
||||
* Gets the operand that represents the new value written by the memory write.
|
||||
*/
|
||||
final Instruction getPartial() {
|
||||
result = getPartialOperand().getDefinitionInstruction()
|
||||
result = getPartialOperand().getDef()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1782,25 +1787,3 @@ class BuiltInInstruction extends Instruction {
|
||||
getOpcode() instanceof BuiltInOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class IndexedElementInstruction extends Instruction {
|
||||
ArrayAccess arrAccess;
|
||||
|
||||
IndexedElementInstruction() {
|
||||
arrAccess = Construction::getInstructionArrayAccess(this)
|
||||
}
|
||||
|
||||
override final string getImmediateString() {
|
||||
result = arrAccess.toString()
|
||||
}
|
||||
|
||||
final ArrayAccess getArrayAccess() {
|
||||
result = arrAccess
|
||||
}
|
||||
}
|
||||
|
||||
class IndexedElementAddressInstruction extends VariableInstruction {
|
||||
IndexedElementAddressInstruction() {
|
||||
getOpcode() instanceof Opcode::IndexedElementAddress
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,47 @@
|
||||
private import internal.IRInternal
|
||||
import Instruction
|
||||
import IRBlock
|
||||
import csharp
|
||||
import semmle.code.csharp.ir.implementation.MemoryAccessKind
|
||||
import semmle.code.csharp.ir.internal.Overlap
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import internal.OperandImports as Imports
|
||||
import Imports::MemoryAccessKind
|
||||
import Imports::Overlap
|
||||
private import Imports::OperandTag
|
||||
|
||||
cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag)
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not isInCycle(useInstr)
|
||||
} or
|
||||
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap) {
|
||||
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap)
|
||||
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
|
||||
not isInCycle(useInstr)
|
||||
} or
|
||||
TPhiOperand(PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap) {
|
||||
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
}
|
||||
|
||||
/** Gets a non-phi instruction that defines an operand of `instr`. */
|
||||
private Instruction getNonPhiOperandDef(Instruction instr) {
|
||||
result = Construction::getRegisterOperandDefinition(instr, _)
|
||||
or
|
||||
result = Construction::getMemoryOperandDefinition(instr, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
*
|
||||
* If such cycles are present, either due to a programming error in the IR
|
||||
* generation or due to a malformed database, it can cause infinite loops in
|
||||
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
|
||||
* better to remove these operands than to leave cycles in the operand graph.
|
||||
*/
|
||||
pragma[noopt]
|
||||
private predicate isInCycle(Instruction instr) {
|
||||
instr instanceof Instruction and
|
||||
getNonPhiOperandDef+(instr) = instr
|
||||
}
|
||||
|
||||
/**
|
||||
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
|
||||
*/
|
||||
@@ -25,26 +50,62 @@ class Operand extends TOperand {
|
||||
result = "Operand"
|
||||
}
|
||||
|
||||
final Location getLocation() {
|
||||
result = getUseInstruction().getLocation()
|
||||
final Language::Location getLocation() {
|
||||
result = getUse().getLocation()
|
||||
}
|
||||
|
||||
final IRFunction getEnclosingIRFunction() {
|
||||
result = getUseInstruction().getEnclosingIRFunction()
|
||||
result = getUse().getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
Instruction getUseInstruction() {
|
||||
Instruction getUse() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand. Unlike
|
||||
* `getDef`, this also has a result when `isDefinitionInexact` holds, which
|
||||
* means that the resulting instruction may only _partially_ or _potentially_
|
||||
* be the value of this operand.
|
||||
*/
|
||||
Instruction getAnyDef() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` whose result is the value of the operand. Unlike
|
||||
* `getAnyDef`, this also has no result when `isDefinitionInexact` holds,
|
||||
* which means that the resulting instruction must always be exactly the be
|
||||
* the value of this operand.
|
||||
*/
|
||||
final Instruction getDef() {
|
||||
result = this.getAnyDef() and
|
||||
getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: renamed to `getUse`.
|
||||
*
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
deprecated
|
||||
final Instruction getUseInstruction() {
|
||||
result = getUse()
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
||||
* predicate is `getAnyDef`, but most uses of this predicate should probably
|
||||
* be replaced with `getDef`.
|
||||
*
|
||||
* Gets the `Instruction` whose result is the value of the operand.
|
||||
*/
|
||||
Instruction getDefinitionInstruction() {
|
||||
none()
|
||||
deprecated
|
||||
final Instruction getDefinitionInstruction() {
|
||||
result = getAnyDef()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +137,7 @@ class Operand extends TOperand {
|
||||
* For example: `this:r3_5`
|
||||
*/
|
||||
final string getDumpString() {
|
||||
result = getDumpLabel() + getInexactSpecifier() + getDefinitionInstruction().getResultId()
|
||||
result = getDumpLabel() + getInexactSpecifier() + getAnyDef().getResultId()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,8 +166,8 @@ class Operand extends TOperand {
|
||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||
* has been cast to a different type.
|
||||
*/
|
||||
Type getType() {
|
||||
result = getDefinitionInstruction().getResultType()
|
||||
Language::Type getType() {
|
||||
result = getAnyDef().getResultType()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,8 +177,8 @@ class Operand extends TOperand {
|
||||
* not hold, the value of the operand represents a value whose type is
|
||||
* given by `getResultType()`.
|
||||
*/
|
||||
predicate isLValue() {
|
||||
getDefinitionInstruction().isLValue()
|
||||
predicate isGLValue() {
|
||||
getAnyDef().isGLValue()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,7 +186,7 @@ class Operand extends TOperand {
|
||||
* a known constant size, this predicate does not hold.
|
||||
*/
|
||||
int getSize() {
|
||||
result = 8 //getType().getSize() TODO: C# memory layout
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +199,7 @@ class MemoryOperand extends Operand {
|
||||
this = TPhiOperand(_, _, _, _)
|
||||
}
|
||||
|
||||
override predicate isLValue() {
|
||||
override predicate isGLValue() {
|
||||
// A `MemoryOperand` can never be a glvalue
|
||||
none()
|
||||
}
|
||||
@@ -157,7 +218,7 @@ class MemoryOperand extends Operand {
|
||||
*/
|
||||
final AddressOperand getAddressOperand() {
|
||||
getMemoryAccess().usesAddressOperand() and
|
||||
result.getUseInstruction() = getUseInstruction()
|
||||
result.getUse() = getUse()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,11 +235,11 @@ class NonPhiOperand extends Operand {
|
||||
this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _)
|
||||
}
|
||||
|
||||
override final Instruction getUseInstruction() {
|
||||
override final Instruction getUse() {
|
||||
result = useInstr
|
||||
}
|
||||
|
||||
override final Instruction getDefinitionInstruction() {
|
||||
override final Instruction getAnyDef() {
|
||||
result = defInstr
|
||||
}
|
||||
|
||||
@@ -223,7 +284,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
||||
class TypedOperand extends NonPhiMemoryOperand {
|
||||
override TypedOperandTag tag;
|
||||
|
||||
override final Type getType() {
|
||||
override final Language::Type getType() {
|
||||
result = Construction::getInstructionOperandType(useInstr, tag)
|
||||
}
|
||||
}
|
||||
@@ -386,11 +447,10 @@ class SideEffectOperand extends TypedOperand {
|
||||
override SideEffectOperandTag tag;
|
||||
|
||||
override final int getSize() {
|
||||
if getType() instanceof UnknownType then
|
||||
if getType() instanceof Language::UnknownType then
|
||||
result = Construction::getInstructionOperandSize(useInstr, tag)
|
||||
else
|
||||
// TODO: Memory layout in C#
|
||||
result = 8 //getType().getSize()
|
||||
result = Language::getTypeSize(getType())
|
||||
}
|
||||
|
||||
override MemoryAccessKind getMemoryAccess() {
|
||||
@@ -437,11 +497,11 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
||||
result = "Phi"
|
||||
}
|
||||
|
||||
override final PhiInstruction getUseInstruction() {
|
||||
override final PhiInstruction getUse() {
|
||||
result = useInstr
|
||||
}
|
||||
|
||||
override final Instruction getDefinitionInstruction() {
|
||||
override final Instruction getAnyDef() {
|
||||
result = defInstr
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
private import internal.IRInternal
|
||||
private import IR
|
||||
import csharp
|
||||
import semmle.code.csharp.ir.IRConfiguration
|
||||
//private import semmle.code.csharp.Print
|
||||
private import internal.PrintIRImports as Imports
|
||||
import Imports::IRConfiguration
|
||||
|
||||
private newtype TPrintIRConfiguration = MkPrintIRConfiguration()
|
||||
|
||||
@@ -17,12 +17,12 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
|
||||
* Holds if the IR for `func` should be printed. By default, holds for all
|
||||
* functions.
|
||||
*/
|
||||
predicate shouldPrintFunction(Callable func) {
|
||||
predicate shouldPrintFunction(Language::Function func) {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
private predicate shouldPrintFunction(Callable func) {
|
||||
private predicate shouldPrintFunction(Language::Function func) {
|
||||
exists(PrintIRConfiguration config |
|
||||
config.shouldPrintFunction(func)
|
||||
)
|
||||
@@ -32,7 +32,7 @@ private predicate shouldPrintFunction(Callable func) {
|
||||
* Override of `IRConfiguration` to only create IR for the functions that are to be dumped.
|
||||
*/
|
||||
private class FilteredIRConfiguration extends IRConfiguration {
|
||||
override predicate shouldCreateIRForFunction(Callable func) {
|
||||
override predicate shouldCreateIRForFunction(Language::Function func) {
|
||||
shouldPrintFunction(func)
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ abstract class PrintableIRNode extends TPrintableIRNode {
|
||||
/**
|
||||
* Gets the location to be emitted for the node.
|
||||
*/
|
||||
abstract Location getLocation();
|
||||
abstract Language::Location getLocation();
|
||||
|
||||
/**
|
||||
* Gets the label to be emitted for the node.
|
||||
@@ -126,17 +126,16 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
|
||||
result = irFunc.toString()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
override Language::Location getLocation() {
|
||||
result = irFunc.getLocation()
|
||||
}
|
||||
|
||||
override string getLabel() {
|
||||
// TODO: C++ USED THE PRINT MODULE, NOT SURE TOsTRING DOES THE JOB
|
||||
result = irFunc.getFunction().toString()
|
||||
result = Language::getIdentityString(irFunc.getFunction())
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
this = rank[result + 1](PrintableIRFunction orderedFunc, Location location |
|
||||
this = rank[result + 1](PrintableIRFunction orderedFunc, Language::Location location |
|
||||
location = orderedFunc.getIRFunction().getLocation() |
|
||||
orderedFunc order by location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), orderedFunc.getLabel()
|
||||
@@ -166,7 +165,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock {
|
||||
result = getLabel()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
override Language::Location getLocation() {
|
||||
result = block.getLocation()
|
||||
}
|
||||
|
||||
@@ -214,7 +213,7 @@ class PrintableInstruction extends PrintableIRNode, TPrintableInstruction {
|
||||
result = instr.toString()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
override Language::Location getLocation() {
|
||||
result = instr.getLocation()
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind
|
||||
@@ -1,6 +1,6 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.ir.implementation.raw.IR
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
@@ -30,6 +30,10 @@ cached private module Cached {
|
||||
element.hasInstruction(_, tag, _, _)
|
||||
}
|
||||
|
||||
cached predicate hasUserVariable(Callable callable, Variable var, Type type) {
|
||||
getTranslatedFunction(callable).hasUserVariable(var, type)
|
||||
}
|
||||
|
||||
cached predicate hasTempVariable(Callable callable, Locatable ast, TempVariableTag tag,
|
||||
Type type) {
|
||||
exists(TranslatedElement element |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind
|
||||
import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
@@ -1 +1,2 @@
|
||||
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
import IRConstruction as Construction
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag
|
||||
import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities
|
||||
import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag
|
||||
import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable
|
||||
@@ -0,0 +1,4 @@
|
||||
import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind
|
||||
import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.csharp.ir.implementation.Opcode as Opcode
|
||||
import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag
|
||||
@@ -0,0 +1,3 @@
|
||||
import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.csharp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag
|
||||
@@ -0,0 +1 @@
|
||||
import semmle.code.csharp.ir.IRConfiguration as IRConfiguration
|
||||
@@ -1,6 +1,6 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.ir.implementation.Opcode
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.ir.implementation.Opcode
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.ir.implementation.Opcode
|
||||
private import semmle.code.csharp.ir.internal.IRUtilities
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import csharp
|
||||
import csharp
|
||||
import semmle.code.csharp.ir.implementation.raw.IR
|
||||
private import semmle.code.csharp.ir.IRConfiguration
|
||||
private import semmle.code.csharp.ir.implementation.Opcode
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.ir.implementation.Opcode
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
|
||||
@@ -2,7 +2,7 @@ import csharp
|
||||
import semmle.code.csharp.ir.implementation.raw.IR
|
||||
private import semmle.code.csharp.ir.implementation.Opcode
|
||||
private import semmle.code.csharp.ir.internal.IRUtilities
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.internal.TempVariableTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
@@ -315,6 +315,25 @@ class TranslatedFunction extends TranslatedElement,
|
||||
result = callable.getDeclaringType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this function defines or accesses variable `var` with type `type`. This includes all
|
||||
* parameters and local variables, plus any static fields that are directly accessed by the
|
||||
* function.
|
||||
*/
|
||||
final predicate hasUserVariable(Variable var, Type type) {
|
||||
(
|
||||
(
|
||||
var.(Member).isStatic() and
|
||||
exists(VariableAccess access |
|
||||
access.getTarget() = var and
|
||||
access.getEnclosingCallable() = callable
|
||||
)
|
||||
) or
|
||||
var.(LocalScopeVariable).getCallable() = callable
|
||||
) and
|
||||
type = getVariableType(var)
|
||||
}
|
||||
|
||||
private final Type getReturnType() {
|
||||
result = callable.getReturnType()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.ir.implementation.Opcode
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.ir.internal.TempVariableTag
|
||||
private import semmle.code.csharp.ir.internal.OperandTag
|
||||
private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
||||
private import InstructionTag
|
||||
private import TranslatedCondition
|
||||
private import TranslatedDeclarationEntry
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
private import csharp as Cpp
|
||||
|
||||
class Function = Cpp::Callable;
|
||||
class Location = Cpp::Location;
|
||||
class AST = Cpp::Element;
|
||||
|
||||
class Type = Cpp::Type;
|
||||
//REVIEW: This might not exist in the database.
|
||||
class UnknownType = Cpp::UnknownType;
|
||||
class VoidType = Cpp::VoidType;
|
||||
class IntegralType = Cpp::IntegralType;
|
||||
class FloatingPointType = Cpp::FloatingPointType;
|
||||
|
||||
private newtype TClassDerivation =
|
||||
// Note that this is the `Class` type exported from this module, not CSharp::Class.
|
||||
MkClassDerivation(Class base, Class derived) {
|
||||
derived.getABaseType() = base
|
||||
}
|
||||
|
||||
class ClassDerivation extends MkClassDerivation {
|
||||
Class baseClass;
|
||||
Class derivedClass;
|
||||
|
||||
ClassDerivation() {
|
||||
this = MkClassDerivation(baseClass, derivedClass)
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = "ClassDerivation"
|
||||
}
|
||||
|
||||
final Class getBaseClass() {
|
||||
result = baseClass
|
||||
}
|
||||
|
||||
final Class getDerivedClass() {
|
||||
result = derivedClass
|
||||
}
|
||||
|
||||
final int getByteOffset() {
|
||||
// Inheritance never requires adjusting the `this` pointer in C#.
|
||||
result = 0
|
||||
}
|
||||
}
|
||||
|
||||
class StringLiteral = Cpp::StringLiteral;
|
||||
|
||||
class Variable = Cpp::Variable;
|
||||
class AutomaticVariable = Cpp::LocalScopeVariable;
|
||||
class StaticVariable = Cpp::Variable;
|
||||
class Parameter = Cpp::Parameter;
|
||||
class Field = Cpp::Field;
|
||||
|
||||
// TODO: Remove necessity for these.
|
||||
class Expr = Cpp::Expr;
|
||||
class Class = Cpp::RefType; // Used for inheritance conversions
|
||||
|
||||
string getIdentityString(Function func) {
|
||||
// REVIEW: Is this enough to make it unique?
|
||||
// result = func.getQualifiedName()
|
||||
result = func.getName()
|
||||
}
|
||||
|
||||
predicate hasCaseEdge(string minValue, string maxValue) {
|
||||
// TODO: Need to handle `switch` statements that switch on an integer.
|
||||
none()
|
||||
}
|
||||
|
||||
predicate hasPositionalArgIndex(int argIndex) {
|
||||
exists(Cpp::MethodCall call |
|
||||
exists(call.getArgument(argIndex))
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasAsmOperandIndex(int operandIndex) {
|
||||
none()
|
||||
}
|
||||
|
||||
int getTypeSize(Type type) {
|
||||
// REVIEW: Is this complete?
|
||||
result = type.(Cpp::SimpleType).getSize() or
|
||||
result = getTypeSize(type.(Cpp::Enum).getUnderlyingType()) or
|
||||
// TODO: Generate a reasonable size
|
||||
type instanceof Cpp::Struct and result = 16 or
|
||||
type instanceof Cpp::RefType and result = getPointerSize() or
|
||||
type instanceof Cpp::PointerType and result = getPointerSize() or
|
||||
result = getTypeSize(type.(Cpp::TupleType).getUnderlyingType()) or
|
||||
// TODO: Add room for extra field
|
||||
result = getTypeSize(type.(Cpp::NullableType).getUnderlyingType()) or
|
||||
type instanceof Cpp::VoidType and result = 0
|
||||
}
|
||||
|
||||
int getPointerSize() {
|
||||
// TODO: Deal with sizes in general
|
||||
result = 8
|
||||
}
|
||||
|
||||
predicate isVariableAutomatic(Variable var) {
|
||||
var instanceof Cpp::LocalScopeVariable
|
||||
}
|
||||
|
||||
string getStringLiteralText(StringLiteral s) {
|
||||
// REVIEW: Is this the right escaping?
|
||||
result = s.toString()
|
||||
}
|
||||
|
||||
predicate hasPotentialLoop(Function f) {
|
||||
exists(Cpp::LoopStmt l | l.getEnclosingCallable() = f) or
|
||||
exists(Cpp::GotoStmt s | s.getEnclosingCallable() = f)
|
||||
}
|
||||
|
||||
predicate hasGoto(Function f) {
|
||||
exists(Cpp::GotoStmt s | s.getEnclosingCallable() = f)
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
import csharp
|
||||
|
||||
class IntValue = int;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import csharp
|
||||
|
||||
private newtype TOverlap =
|
||||
TMayPartiallyOverlap() or
|
||||
TMustTotallyOverlap() or
|
||||
|
||||
@@ -1,135 +1,135 @@
|
||||
array_acc.cs:
|
||||
# 4| f
|
||||
# 4| Block 0
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(lval<array_init_and_access>) = InitializeThis :
|
||||
# 5| r0_4(lval<Int32[]>) = VariableAddress[arr] :
|
||||
# 5| mu0_5(Int32[]) = Uninitialized[arr] : &:r0_4
|
||||
# 5| r0_6(Int32) = Constant[0] :
|
||||
# 5| r0_7(lval<Int32>) = IndexedElementAddress : r0_4, r0_6
|
||||
# 5| r0_8(Int32) = Constant[101] :
|
||||
# 5| mu0_9(Int32) = Store : &:r0_7, r0_8
|
||||
# 5| r0_10(Int32) = Constant[1] :
|
||||
# 5| r0_11(lval<Int32>) = IndexedElementAddress : r0_4, r0_10
|
||||
# 5| r0_12(Int32) = Constant[102] :
|
||||
# 5| mu0_13(Int32) = Store : &:r0_11, r0_12
|
||||
# 6| r0_14(Int32) = Constant[5] :
|
||||
# 6| r0_15(lval<Int32[]>) = VariableAddress[arr] :
|
||||
# 6| r0_16(Int32) = Constant[1] :
|
||||
# 6| r0_17(lval<Int32>) = IndexedElementAddress : r0_15, r0_16
|
||||
# 6| mu0_18(Int32) = Store : &:r0_17, r0_14
|
||||
# 4| v0_19(Void) = ReturnVoid :
|
||||
# 4| v0_20(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_21(Void) = ExitFunction :
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(glval<array_init_and_access>) = InitializeThis :
|
||||
# 5| r0_4(glval<Int32[]>) = VariableAddress[arr] :
|
||||
# 5| mu0_5(Int32[]) = Uninitialized[arr] : &:r0_4
|
||||
# 5| r0_6(Int32) = Constant[0] :
|
||||
# 5| r0_7(glval<Int32>) = IndexedElementAddress : r0_4, r0_6
|
||||
# 5| r0_8(Int32) = Constant[101] :
|
||||
# 5| mu0_9(Int32) = Store : &:r0_7, r0_8
|
||||
# 5| r0_10(Int32) = Constant[1] :
|
||||
# 5| r0_11(glval<Int32>) = IndexedElementAddress : r0_4, r0_10
|
||||
# 5| r0_12(Int32) = Constant[102] :
|
||||
# 5| mu0_13(Int32) = Store : &:r0_11, r0_12
|
||||
# 6| r0_14(Int32) = Constant[5] :
|
||||
# 6| r0_15(glval<Int32[]>) = VariableAddress[arr] :
|
||||
# 6| r0_16(Int32) = Constant[1] :
|
||||
# 6| r0_17(glval<Int32>) = IndexedElementAddress : r0_15, r0_16
|
||||
# 6| mu0_18(Int32) = Store : &:r0_17, r0_14
|
||||
# 4| v0_19(Void) = ReturnVoid :
|
||||
# 4| v0_20(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_21(Void) = ExitFunction :
|
||||
|
||||
func_with_param_call.cs:
|
||||
# 4| f
|
||||
# 4| Block 0
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(lval<test_call_with_param>) = InitializeThis :
|
||||
# 4| r0_4(lval<Int32>) = VariableAddress[x] :
|
||||
# 4| mu0_5(Int32) = InitializeParameter[x] : &:r0_4
|
||||
# 4| r0_6(lval<Int32>) = VariableAddress[y] :
|
||||
# 4| mu0_7(Int32) = InitializeParameter[y] : &:r0_6
|
||||
# 5| r0_8(lval<Int32>) = VariableAddress[#return] :
|
||||
# 5| r0_9(lval<Int32>) = VariableAddress[x] :
|
||||
# 5| r0_10(Int32) = Load : &:r0_9, ~mu0_2
|
||||
# 5| r0_11(lval<Int32>) = VariableAddress[y] :
|
||||
# 5| r0_12(Int32) = Load : &:r0_11, ~mu0_2
|
||||
# 5| r0_13(Int32) = Add : r0_10, r0_12
|
||||
# 5| mu0_14(Int32) = Store : &:r0_8, r0_13
|
||||
# 4| r0_15(lval<Int32>) = VariableAddress[#return] :
|
||||
# 4| v0_16(Void) = ReturnValue : &:r0_15, ~mu0_2
|
||||
# 4| v0_17(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_18(Void) = ExitFunction :
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(glval<test_call_with_param>) = InitializeThis :
|
||||
# 4| r0_4(glval<Int32>) = VariableAddress[x] :
|
||||
# 4| mu0_5(Int32) = InitializeParameter[x] : &:r0_4
|
||||
# 4| r0_6(glval<Int32>) = VariableAddress[y] :
|
||||
# 4| mu0_7(Int32) = InitializeParameter[y] : &:r0_6
|
||||
# 5| r0_8(glval<Int32>) = VariableAddress[#return] :
|
||||
# 5| r0_9(glval<Int32>) = VariableAddress[x] :
|
||||
# 5| r0_10(Int32) = Load : &:r0_9, ~mu0_2
|
||||
# 5| r0_11(glval<Int32>) = VariableAddress[y] :
|
||||
# 5| r0_12(Int32) = Load : &:r0_11, ~mu0_2
|
||||
# 5| r0_13(Int32) = Add : r0_10, r0_12
|
||||
# 5| mu0_14(Int32) = Store : &:r0_8, r0_13
|
||||
# 4| r0_15(glval<Int32>) = VariableAddress[#return] :
|
||||
# 4| v0_16(Void) = ReturnValue : &:r0_15, ~mu0_2
|
||||
# 4| v0_17(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_18(Void) = ExitFunction :
|
||||
|
||||
# 8| g
|
||||
# 8| Block 0
|
||||
# 8| v0_0(Void) = EnterFunction :
|
||||
# 8| mu0_1(Object) = AliasedDefinition :
|
||||
# 8| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 8| r0_3(lval<test_call_with_param>) = InitializeThis :
|
||||
# 9| r0_4(lval<Int32>) = VariableAddress[#return] :
|
||||
# 9| r0_5(lval<Int32>) = FunctionAddress[f] :
|
||||
# 9| r0_6(Int32) = Constant[2] :
|
||||
# 9| r0_7(Int32) = Constant[3] :
|
||||
# 9| r0_8(Int32) = Call : func:r0_5, 0:r0_6, 1:r0_7
|
||||
# 9| v0_9(Void) = ^CallSideEffect : ~mu0_2
|
||||
# 9| mu0_10(Int32) = Store : &:r0_4, r0_8
|
||||
# 8| r0_11(lval<Int32>) = VariableAddress[#return] :
|
||||
# 8| v0_12(Void) = ReturnValue : &:r0_11, ~mu0_2
|
||||
# 8| v0_13(Void) = UnmodeledUse : mu*
|
||||
# 8| v0_14(Void) = ExitFunction :
|
||||
# 8| v0_0(Void) = EnterFunction :
|
||||
# 8| mu0_1(Object) = AliasedDefinition :
|
||||
# 8| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 8| r0_3(glval<test_call_with_param>) = InitializeThis :
|
||||
# 9| r0_4(glval<Int32>) = VariableAddress[#return] :
|
||||
# 9| r0_5(glval<Int32>) = FunctionAddress[f] :
|
||||
# 9| r0_6(Int32) = Constant[2] :
|
||||
# 9| r0_7(Int32) = Constant[3] :
|
||||
# 9| r0_8(Int32) = Call : func:r0_5, 0:r0_6, 1:r0_7
|
||||
# 9| v0_9(Void) = ^CallSideEffect : ~mu0_2
|
||||
# 9| mu0_10(Int32) = Store : &:r0_4, r0_8
|
||||
# 8| r0_11(glval<Int32>) = VariableAddress[#return] :
|
||||
# 8| v0_12(Void) = ReturnValue : &:r0_11, ~mu0_2
|
||||
# 8| v0_13(Void) = UnmodeledUse : mu*
|
||||
# 8| v0_14(Void) = ExitFunction :
|
||||
|
||||
simple_call.cs:
|
||||
# 4| f
|
||||
# 4| Block 0
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(lval<test_simple_call>) = InitializeThis :
|
||||
# 5| r0_4(lval<Int32>) = VariableAddress[#return] :
|
||||
# 5| r0_5(Int32) = Constant[0] :
|
||||
# 5| mu0_6(Int32) = Store : &:r0_4, r0_5
|
||||
# 4| r0_7(lval<Int32>) = VariableAddress[#return] :
|
||||
# 4| v0_8(Void) = ReturnValue : &:r0_7, ~mu0_2
|
||||
# 4| v0_9(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_10(Void) = ExitFunction :
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(glval<test_simple_call>) = InitializeThis :
|
||||
# 5| r0_4(glval<Int32>) = VariableAddress[#return] :
|
||||
# 5| r0_5(Int32) = Constant[0] :
|
||||
# 5| mu0_6(Int32) = Store : &:r0_4, r0_5
|
||||
# 4| r0_7(glval<Int32>) = VariableAddress[#return] :
|
||||
# 4| v0_8(Void) = ReturnValue : &:r0_7, ~mu0_2
|
||||
# 4| v0_9(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_10(Void) = ExitFunction :
|
||||
|
||||
# 8| g
|
||||
# 8| Block 0
|
||||
# 8| v0_0(Void) = EnterFunction :
|
||||
# 8| mu0_1(Object) = AliasedDefinition :
|
||||
# 8| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 8| r0_3(lval<test_simple_call>) = InitializeThis :
|
||||
# 9| r0_4(lval<Int32>) = VariableAddress[#return] :
|
||||
# 9| r0_5(lval<Int32>) = FunctionAddress[f] :
|
||||
# 9| r0_6(Int32) = Call : func:r0_5
|
||||
# 9| v0_7(Void) = ^CallSideEffect : ~mu0_2
|
||||
# 9| mu0_8(Int32) = Store : &:r0_4, r0_6
|
||||
# 8| r0_9(lval<Int32>) = VariableAddress[#return] :
|
||||
# 8| v0_10(Void) = ReturnValue : &:r0_9, ~mu0_2
|
||||
# 8| v0_11(Void) = UnmodeledUse : mu*
|
||||
# 8| v0_12(Void) = ExitFunction :
|
||||
# 8| v0_0(Void) = EnterFunction :
|
||||
# 8| mu0_1(Object) = AliasedDefinition :
|
||||
# 8| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 8| r0_3(glval<test_simple_call>) = InitializeThis :
|
||||
# 9| r0_4(glval<Int32>) = VariableAddress[#return] :
|
||||
# 9| r0_5(glval<Int32>) = FunctionAddress[f] :
|
||||
# 9| r0_6(Int32) = Call : func:r0_5
|
||||
# 9| v0_7(Void) = ^CallSideEffect : ~mu0_2
|
||||
# 9| mu0_8(Int32) = Store : &:r0_4, r0_6
|
||||
# 8| r0_9(glval<Int32>) = VariableAddress[#return] :
|
||||
# 8| v0_10(Void) = ReturnValue : &:r0_9, ~mu0_2
|
||||
# 8| v0_11(Void) = UnmodeledUse : mu*
|
||||
# 8| v0_12(Void) = ExitFunction :
|
||||
|
||||
simple_function.cs:
|
||||
# 4| f
|
||||
# 4| Block 0
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(lval<test_simple_function>) = InitializeThis :
|
||||
# 5| r0_4(lval<Int32>) = VariableAddress[#return] :
|
||||
# 5| r0_5(Int32) = Constant[0] :
|
||||
# 5| mu0_6(Int32) = Store : &:r0_4, r0_5
|
||||
# 4| r0_7(lval<Int32>) = VariableAddress[#return] :
|
||||
# 4| v0_8(Void) = ReturnValue : &:r0_7, ~mu0_2
|
||||
# 4| v0_9(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_10(Void) = ExitFunction :
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(glval<test_simple_function>) = InitializeThis :
|
||||
# 5| r0_4(glval<Int32>) = VariableAddress[#return] :
|
||||
# 5| r0_5(Int32) = Constant[0] :
|
||||
# 5| mu0_6(Int32) = Store : &:r0_4, r0_5
|
||||
# 4| r0_7(glval<Int32>) = VariableAddress[#return] :
|
||||
# 4| v0_8(Void) = ReturnValue : &:r0_7, ~mu0_2
|
||||
# 4| v0_9(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_10(Void) = ExitFunction :
|
||||
|
||||
variables.cs:
|
||||
# 4| f
|
||||
# 4| Block 0
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(lval<test_variables>) = InitializeThis :
|
||||
# 5| r0_4(lval<Int32>) = VariableAddress[x] :
|
||||
# 5| mu0_5(Int32) = Uninitialized[x] : &:r0_4
|
||||
# 5| r0_6(lval<Int32>) = VariableAddress[y] :
|
||||
# 5| r0_7(Int32) = Constant[5] :
|
||||
# 5| mu0_8(Int32) = Store : &:r0_6, r0_7
|
||||
# 6| r0_9(Int32) = Constant[4] :
|
||||
# 6| r0_10(lval<Int32>) = VariableAddress[x] :
|
||||
# 6| mu0_11(Int32) = Store : &:r0_10, r0_9
|
||||
# 7| r0_12(lval<Int32>) = VariableAddress[y] :
|
||||
# 7| r0_13(Int32) = Load : &:r0_12, ~mu0_2
|
||||
# 7| r0_14(lval<Int32>) = VariableAddress[x] :
|
||||
# 7| mu0_15(Int32) = Store : &:r0_14, r0_13
|
||||
# 4| v0_16(Void) = ReturnVoid :
|
||||
# 4| v0_17(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_18(Void) = ExitFunction :
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(glval<test_variables>) = InitializeThis :
|
||||
# 5| r0_4(glval<Int32>) = VariableAddress[x] :
|
||||
# 5| mu0_5(Int32) = Uninitialized[x] : &:r0_4
|
||||
# 5| r0_6(glval<Int32>) = VariableAddress[y] :
|
||||
# 5| r0_7(Int32) = Constant[5] :
|
||||
# 5| mu0_8(Int32) = Store : &:r0_6, r0_7
|
||||
# 6| r0_9(Int32) = Constant[4] :
|
||||
# 6| r0_10(glval<Int32>) = VariableAddress[x] :
|
||||
# 6| mu0_11(Int32) = Store : &:r0_10, r0_9
|
||||
# 7| r0_12(glval<Int32>) = VariableAddress[y] :
|
||||
# 7| r0_13(Int32) = Load : &:r0_12, ~mu0_2
|
||||
# 7| r0_14(glval<Int32>) = VariableAddress[x] :
|
||||
# 7| mu0_15(Int32) = Store : &:r0_14, r0_13
|
||||
# 4| v0_16(Void) = ReturnVoid :
|
||||
# 4| v0_17(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_18(Void) = ExitFunction :
|
||||
|
||||
Reference in New Issue
Block a user