Merge pull request #1845 from AndreiDiaconu1/ircsharp-compiler-generated

C# IR: Framework for translating compiler generated elements
This commit is contained in:
Calum Grant
2019-09-09 15:42:07 +01:00
committed by GitHub
32 changed files with 2433 additions and 492 deletions

View File

@@ -7,6 +7,7 @@ private import TranslatedCondition
private import TranslatedElement
private import TranslatedExpr
private import TranslatedStmt
private import desugar.Foreach
private import TranslatedFunction
private import semmle.code.csharp.ir.Util
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
@@ -136,6 +137,17 @@ private module Cached {
)
)
or
// Compiler generated foreach while loop:
// Same as above
exists(TranslatedForeachWhile s |
result = s.getFirstInstruction() and
exists(TranslatedElement inBody, InstructionTag tag |
result = inBody.getInstructionSuccessor(tag, kind) and
exists(TranslatedElement body | body = s.getBody() | inBody = body.getAChild*()) and
instruction = inBody.getInstruction(tag)
)
)
or
// Do-while loop:
// The back edge should be the edge(s) from the condition to the
// body. This ensures that it's the back edge that will be pruned in a `do

View File

@@ -1,9 +1,6 @@
import csharp
import semmle.code.csharp.ir.Util
//private predicate fieldIsInitialized(Field field) {
// exists(field.getInitializer())
//}
private predicate elementIsInitialized(int elementIndex) {
exists(ArrayInitWithMod initList | initList.isInitialized(elementIndex))
}
@@ -54,6 +51,7 @@ newtype TInstructionTag =
BoolConversionConstantTag() or
BoolConversionCompareTag() or
LoadTag() or // Implicit load due to lvalue-to-rvalue conversion
AddressTag() or
CatchTag() or
ThrowTag() or
UnwindTag() or
@@ -192,16 +190,8 @@ string getInstructionTagId(TInstructionTag tag) {
or
tag = GeneratedBranchTag() and result = "GeneratedBranchTag"
or
// TODO: Reread
// exists(Field field, Class cls, int index, string tagName |
// field = cls.getCanonicalMember(index) and
// (
// tag = InitializerFieldAddressTag(field) and tagName = "InitFieldAddr" or
// tag = InitializerFieldDefaultValueTag(field) and tagName = "InitFieldDefVal" or
// tag = InitializerFieldDefaultValueStoreTag(field) and tagName = "InitFieldDefValStore"
// ) and
// result = tagName + "(" + index + ")"
// ) or
tag = AddressTag() and result = "AddressTag"
or
exists(int index, string tagName |
(
tag = InitializerElementIndexTag(index) and tagName = "InitElemIndex"

View File

@@ -5,267 +5,55 @@ private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
private import semmle.code.csharp.ir.Util
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
/**
* The IR translation of a call to a function. The call may be from an actual
* call in the source code, or could be a call that is part of the translation
* of a higher-level constructor (e.g. the allocator call in a `NewExpr`).
* The IR translation of a call to a function. The function can be a normal function
* (ie. `MethodCall`) or a constructor call (ie. `ObjectCreation`). Notice that the
* AST generated translated calls are tied to an expression (unlike compiler generated ones,
* which can be attached to either a statement or an expression).
*/
abstract class TranslatedCall extends TranslatedExpr {
final override TranslatedElement getChild(int id) {
// We choose the child's id in the order of evaluation.
// The qualifier is evaluated before the call target, because the value of
// the call target may depend on the value of the qualifier for virtual
// calls.
id = -2 and result = this.getQualifier()
or
id = -1 and result = this.getCallTarget()
or
result = this.getArgument(id)
}
abstract class TranslatedCall extends TranslatedExpr, TranslatedCallBase {
final override Instruction getResult() { result = TranslatedCallBase.super.getResult() }
final override Instruction getFirstInstruction() {
if exists(this.getQualifier())
then result = this.getQualifier().getFirstInstruction()
else result = this.getFirstCallTargetInstruction()
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = CallTag() and
opcode instanceof Opcode::Call and
resultType = getCallResultType() and
isLValue = false
or
hasSideEffect() and
tag = CallSideEffectTag() and
(
if hasWriteSideEffect()
then (
opcode instanceof Opcode::CallSideEffect and
resultType instanceof Language::UnknownType
) else (
opcode instanceof Opcode::CallReadSideEffect and
resultType instanceof Language::UnknownType
)
) and
isLValue = false
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getQualifier() and
result = this.getFirstCallTargetInstruction()
or
child = this.getCallTarget() and
result = this.getFirstArgumentOrCallInstruction()
or
exists(int argIndex |
child = this.getArgument(argIndex) and
if exists(this.getArgument(argIndex + 1))
then result = this.getArgument(argIndex + 1).getFirstInstruction()
else result = this.getInstruction(CallTag())
)
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
(
(
tag = CallTag() and
if this.hasSideEffect()
then result = this.getInstruction(CallSideEffectTag())
else result = this.getParent().getChildSuccessor(this)
)
or
this.hasSideEffect() and
tag = CallSideEffectTag() and
result = this.getParent().getChildSuccessor(this)
)
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = CallTag() and
(
tag = CallTag() and
(
operandTag instanceof CallTargetOperandTag and
result = this.getCallTargetResult()
or
operandTag instanceof ThisArgumentOperandTag and
result = this.getQualifierResult()
or
exists(PositionalArgumentOperandTag argTag |
argTag = operandTag and
result = this.getArgument(argTag.getArgIndex()).getResult()
)
)
)
or
tag = CallSideEffectTag() and
this.hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
override Instruction getUnmodeledDefinitionInstruction() {
result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction()
or
tag = CallSideEffectTag() and
hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
}
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
tag = CallSideEffectTag() and
this.hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result instanceof Language::UnknownType
}
final override Instruction getResult() { result = this.getInstruction(CallTag()) }
/**
* Gets the result type of the call.
*/
abstract Type getCallResultType();
/**
* Holds if the call has a `this` argument.
*/
predicate hasQualifier() { exists(this.getQualifier()) }
/**
* Gets the `TranslatedExpr` for the indirect target of the call, if any.
*/
TranslatedExpr getCallTarget() { none() }
/**
* Gets the first instruction of the sequence to evaluate the call target.
* By default, this is just the first instruction of `getCallTarget()`, but
* it can be overridden by a subclass for cases where there is a call target
* that is not computed from an expression (e.g. a direct call).
*/
Instruction getFirstCallTargetInstruction() {
result = this.getCallTarget().getFirstInstruction()
}
/**
* Gets the instruction whose result value is the target of the call. By
* default, this is just the result of `getCallTarget()`, but it can be
* overridden by a subclass for cases where there is a call target that is not
* computed from an expression (e.g. a direct call).
*/
Instruction getCallTargetResult() { result = this.getCallTarget().getResult() }
/**
* Gets the `TranslatedExpr` for the qualifier of the call (i.e. the value
* that is passed as the `this` argument.
*/
abstract TranslatedExpr getQualifier();
/**
* Gets the instruction whose result value is the `this` argument of the call.
* By default, this is just the result of `getQualifier()`, but it can be
* overridden by a subclass for cases where there is a `this` argument that is
* not computed from a child expression (e.g. a constructor call).
*/
Instruction getQualifierResult() { result = this.getQualifier().getResult() }
/**
* Gets the argument with the specified `index`. Does not include the `this`
* argument.
*/
abstract TranslatedExpr getArgument(int index);
/**
* If there are any arguments, gets the first instruction of the first
* argument. Otherwise, returns the call instruction.
*/
final Instruction getFirstArgumentOrCallInstruction() {
if this.hasArguments()
then result = this.getArgument(0).getFirstInstruction()
else result = this.getInstruction(CallTag())
}
/**
* Holds if the call has any arguments, not counting the `this` argument.
*/
abstract predicate hasArguments();
// TODO: Fix side effects
predicate hasReadSideEffect() { any() }
predicate hasWriteSideEffect() { any() }
private predicate hasSideEffect() { hasReadSideEffect() or hasWriteSideEffect() }
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
this.hasSideEffect() and
tag = CallSideEffectTag() and
result = this.getResult()
}
}
/**
* IR translation of a direct call to a specific function. Used for both
* explicit calls and implicit calls.
* Represents the IR translation of a direct function call. The call can be one of the following:
* `MethodCall`, `LocalFunctionCall`, `AccessorCall`, `OperatorCall`.
* Note that `DelegateCall`s are not treated here since they need to be desugared.
*/
abstract class TranslatedDirectCall extends TranslatedCall {
final override Instruction getFirstCallTargetInstruction() {
result = this.getInstruction(CallTargetTag())
}
final override Instruction getCallTargetResult() { result = this.getInstruction(CallTargetTag()) }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
TranslatedCall.super.hasInstruction(opcode, tag, resultType, isLValue)
or
tag = CallTargetTag() and
opcode instanceof Opcode::FunctionAddress and
resultType = expr.getType() and
isLValue = true
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
result = TranslatedCall.super.getInstructionSuccessor(tag, kind)
or
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = this.getFirstArgumentOrCallInstruction()
}
}
/**
* The IR translation of a call to a function.
*/
abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedCall {
class TranslatedFunctionCall extends TranslatedNonConstantExpr, TranslatedCall {
override Call expr;
override Type getCallResultType() { result = this.getResultType() }
final override predicate hasArguments() { exists(expr.getArgument(0)) }
final override TranslatedExpr getQualifier() {
expr instanceof QualifiableExpr and
result = getTranslatedExpr(expr.(QualifiableExpr).getQualifier())
TranslatedFunctionCall() {
expr instanceof MethodCall or
expr instanceof LocalFunctionCall or
expr instanceof AccessorCall or
expr instanceof OperatorCall
}
final override TranslatedExpr getArgument(int index) {
result = getTranslatedExpr(expr.getArgument(index))
}
}
/**
* Represents the IR translation of a direct function call.
*/
class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
override Call expr;
override Callable getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = expr.getTarget()
}
override TranslatedExpr getArgument(int index) {
result = getTranslatedExpr(expr.getArgument(index))
}
override TranslatedExpr getQualifier() {
expr instanceof QualifiableExpr and
result = getTranslatedExpr(expr.(QualifiableExpr).getQualifier())
}
override Instruction getQualifierResult() { result = this.getQualifier().getResult() }
override Type getCallResultType() { result = expr.getTarget().getReturnType() }
override predicate hasReadSideEffect() {
not expr.getTarget().(SideEffectFunction).neverReadsMemory()
}
@@ -276,26 +64,37 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
}
/**
* Represents the IR translation of a call to a constructor.
* The target of the call is a newly allocated object whose address, after
* the constructor call, address will be passed to a variable declaration.
* Represents the IR translation of a call to a constructor or to a constructor initializer.
* The qualifier of the call is obtained from the constructor call context.
* Note that `DelegateCreation` is not present here, since the call to a delegate constructor is
* compiler generated.
*/
class TranslatedConstructorCall extends TranslatedFunctionCall {
class TranslatedConstructorCall extends TranslatedNonConstantExpr, TranslatedCall {
override Call expr;
TranslatedConstructorCall() {
expr instanceof ObjectCreation or
expr instanceof ConstructorInitializer
}
override Callable getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and result = expr.getTarget()
}
override TranslatedExpr getArgument(int index) {
result = getTranslatedExpr(expr.getArgument(index))
}
// The qualifier for a constructor call has already been generated
// (the `NewObj` instruction)
override TranslatedExpr getQualifier() { none() }
override Type getCallResultType() { result instanceof VoidType }
override Instruction getQualifierResult() {
// We must retrieve the qualifier from the context the
// constructor call happened
exists(StructorCallContext context |
exists(ConstructorCallContext context |
context = this.getParent() and
result = context.getReceiver()
)
}
override Type getCallResultType() { result instanceof VoidType }
override predicate hasQualifier() { any() }
}

View File

@@ -4,25 +4,18 @@ private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
private import common.TranslatedConditionBase
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class ConditionContext extends TranslatedElement {
abstract Instruction getChildTrueSuccessor(TranslatedCondition child);
abstract Instruction getChildFalseSuccessor(TranslatedCondition child);
}
TranslatedCondition getTranslatedCondition(Expr expr) { result.getExpr() = expr }
abstract class TranslatedCondition extends TranslatedElement {
abstract class TranslatedCondition extends ConditionBase {
Expr expr;
final override string toString() { result = expr.toString() }
final override Language::AST getAST() { result = expr }
final ConditionContext getConditionContext() { result = this.getParent() }
final Expr getExpr() { result = expr }
final override Callable getFunction() { result = expr.getEnclosingCallable() }
@@ -56,12 +49,12 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio
class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
override ParenthesizedExpr expr;
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
final override Instruction getChildTrueSuccessor(ConditionBase child) {
child = this.getOperand() and
result = this.getConditionContext().getChildTrueSuccessor(this)
}
final override Instruction getChildFalseSuccessor(TranslatedCondition child) {
final override Instruction getChildFalseSuccessor(ConditionBase child) {
child = this.getOperand() and
result = this.getConditionContext().getChildFalseSuccessor(this)
}
@@ -74,12 +67,12 @@ class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
class TranslatedNotCondition extends TranslatedFlexibleCondition {
override LogicalNotExpr expr;
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
override Instruction getChildTrueSuccessor(ConditionBase child) {
child = this.getOperand() and
result = this.getConditionContext().getChildFalseSuccessor(this)
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
override Instruction getChildFalseSuccessor(ConditionBase child) {
child = this.getOperand() and
result = this.getConditionContext().getChildTrueSuccessor(this)
}
@@ -131,7 +124,7 @@ abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeConditio
class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
TranslatedLogicalAndExpr() { expr instanceof LogicalAndExpr }
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
override Instruction getChildTrueSuccessor(ConditionBase child) {
child = this.getLeftOperand() and
result = this.getRightOperand().getFirstInstruction()
or
@@ -139,7 +132,7 @@ class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
result = this.getConditionContext().getChildTrueSuccessor(this)
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
override Instruction getChildFalseSuccessor(ConditionBase child) {
child = this.getAnOperand() and
result = this.getConditionContext().getChildFalseSuccessor(this)
}
@@ -148,12 +141,12 @@ class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
override LogicalOrExpr expr;
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
override Instruction getChildTrueSuccessor(ConditionBase child) {
child = getAnOperand() and
result = this.getConditionContext().getChildTrueSuccessor(this)
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
override Instruction getChildFalseSuccessor(ConditionBase child) {
child = this.getLeftOperand() and
result = getRightOperand().getFirstInstruction()
or
@@ -162,43 +155,11 @@ class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
}
}
class TranslatedValueCondition extends TranslatedCondition, TTranslatedValueCondition {
class TranslatedValueCondition extends TranslatedCondition, ValueConditionBase,
TTranslatedValueCondition {
TranslatedValueCondition() { this = TTranslatedValueCondition(expr) }
override TranslatedElement getChild(int id) { id = 0 and result = getValueExpr() }
override TranslatedExpr getValueExpr() { result = getTranslatedExpr(expr) }
override Instruction getFirstInstruction() { result = this.getValueExpr().getFirstInstruction() }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = ValueConditionConditionalBranchTag() and
opcode instanceof Opcode::ConditionalBranch and
resultType instanceof VoidType and
isLValue = false
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getValueExpr() and
result = this.getInstruction(ValueConditionConditionalBranchTag())
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = ValueConditionConditionalBranchTag() and
(
kind instanceof TrueEdge and
result = this.getConditionContext().getChildTrueSuccessor(this)
or
kind instanceof FalseEdge and
result = this.getConditionContext().getChildFalseSuccessor(this)
)
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = ValueConditionConditionalBranchTag() and
operandTag instanceof ConditionOperandTag and
result = this.getValueExpr().getResult()
}
private TranslatedExpr getValueExpr() { result = getTranslatedExpr(expr) }
override Instruction valueExprResult() { result = this.getValueExpr().getResult() }
}

View File

@@ -7,6 +7,7 @@ private import TranslatedElement
private import TranslatedExpr
private import TranslatedInitialization
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
private import common.TranslatedDeclarationBase
/**
* Gets the `TranslatedDeclaration` that represents the declaration
@@ -35,59 +36,21 @@ abstract class TranslatedLocalDeclaration extends TranslatedElement, TTranslated
* Represents the IR translation of the declaration of a local variable,
* including its initialization, if any.
*/
class TranslatedLocalVariableDeclaration extends TranslatedLocalDeclaration, InitializationContext {
class TranslatedLocalVariableDeclaration extends TranslatedLocalDeclaration,
LocalVariableDeclarationBase, InitializationContext {
LocalVariable var;
TranslatedLocalVariableDeclaration() { var = expr.getVariable() }
override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() }
override Instruction getFirstInstruction() {
override Instruction getTargetAddress() {
result = this.getInstruction(InitializerVariableAddressTag())
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = getVariableType(var) and
isLValue = true
or
this.hasUninitializedInstruction() and
tag = InitializerStoreTag() and
opcode instanceof Opcode::Uninitialized and
resultType = getVariableType(var) and
isLValue = false
}
override LocalVariable getDeclVar() { result = var }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
(
tag = InitializerVariableAddressTag() and
kind instanceof GotoEdge and
if this.hasUninitializedInstruction()
then result = this.getInstruction(InitializerStoreTag())
else
if this.isInitializedByExpr()
then
// initialization is done by the expression
result = this.getParent().getChildSuccessor(this)
else result = this.getInitialization().getFirstInstruction()
)
or
this.hasUninitializedInstruction() and
kind instanceof GotoEdge and
tag = InitializerStoreTag() and
(
result = this.getInitialization().getFirstInstruction()
or
not exists(this.getInitialization()) and result = this.getParent().getChildSuccessor(this)
)
}
override Type getVarType() { result = getVariableType(getDeclVar()) }
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getInitialization() and result = this.getParent().getChildSuccessor(this)
}
override Type getTargetType() { result = getVariableType(var) }
override IRVariable getInstructionVariable(InstructionTag tag) {
(
@@ -95,23 +58,10 @@ class TranslatedLocalVariableDeclaration extends TranslatedLocalDeclaration, Ini
or
this.hasUninitializedInstruction() and tag = InitializerStoreTag()
) and
result = getIRUserVariable(getFunction(), var)
result = getIRUserVariable(getFunction(), getDeclVar())
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
this.hasUninitializedInstruction() and
tag = InitializerStoreTag() and
operandTag instanceof AddressOperandTag and
result = this.getInstruction(InitializerVariableAddressTag())
}
override Instruction getTargetAddress() {
result = this.getInstruction(InitializerVariableAddressTag())
}
override Type getTargetType() { result = getVariableType(var) }
private TranslatedInitialization getInitialization() {
override TranslatedInitialization getInitialization() {
// First complex initializations
if var.getInitializer() instanceof ArrayCreation
then result = getTranslatedInitialization(var.getInitializer().(ArrayCreation).getInitializer())
@@ -123,17 +73,5 @@ class TranslatedLocalVariableDeclaration extends TranslatedLocalDeclaration, Ini
result = getTranslatedInitialization(var.getInitializer())
}
private predicate hasUninitializedInstruction() {
(
not exists(this.getInitialization()) or
this.getInitialization() instanceof TranslatedListInitialization
) and
not this.isInitializedByExpr()
}
/**
* Predicate that holds if a declaration is not explicitly initialized,
* but will be initialized as part of an expression.
*/
private predicate isInitializedByExpr() { expr.getParent() instanceof IsExpr }
override predicate isInitializedByElement() { expr.getParent() instanceof IsExpr }
}

View File

@@ -11,6 +11,9 @@ private import TranslatedStmt
private import IRConstruction
private import semmle.code.csharp.ir.Util
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
private import desugar.Foreach
private import desugar.Delegate
private import desugar.Lock
/**
* Gets the built-in `int` type.
@@ -22,6 +25,17 @@ ArrayType getArrayOfDim(int dim, Type type) {
result.getElementType() = type
}
private predicate canCreateCompilerGeneratedElement(Element generatedBy, int nth) {
generatedBy instanceof ForeachStmt and nth in [0 .. ForeachElements::noGeneratedElements()]
or
generatedBy instanceof LockStmt and nth in [0 .. LockElements::noGeneratedElements()]
or
generatedBy instanceof DelegateCreation and
nth in [0 .. DelegateElements::noGeneratedElements(generatedBy)]
or
generatedBy instanceof DelegateCall and nth in [0 .. DelegateElements::noGeneratedElements(generatedBy)]
}
/**
* Gets the "real" parent of `expr`. This predicate treats conversions as if
* they were explicit nodes in the expression tree, rather than as implicit
@@ -55,6 +69,11 @@ private predicate ignoreExprAndDescendants(Expr expr) {
// constant value.
isIRConstant(getRealParent(expr))
or
// Ignore the local declaration done by a `ForeachStmt`
// since we desugar it
expr instanceof LocalVariableDeclExpr and
expr.getParent() instanceof ForeachStmt
or
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
}
@@ -202,12 +221,15 @@ newtype TTranslatedElement =
exists(LocalVariableDeclAndInitExpr lvInit |
lvInit.getInitializer() = expr and
not expr instanceof ArrayCreation and
not expr instanceof ObjectCreation
not expr instanceof ObjectCreation and
not expr instanceof DelegateCreation
)
or
// Then treat more complex ones
expr instanceof ObjectCreation
or
expr instanceof DelegateCreation
or
expr instanceof ArrayInitializer
or
expr instanceof ObjectInitializer
@@ -253,7 +275,16 @@ newtype TTranslatedElement =
)
} or
// A local declaration
TTranslatedDeclaration(LocalVariableDeclExpr entry)
TTranslatedDeclaration(LocalVariableDeclExpr entry) {
// foreach var decl and init is treated separately,
// because foreach needs desugaring
not ignoreExprAndDescendants(entry)
} or
// A compiler generated element, generated by `generatedBy` during the
// desugaring process
TTranslatedCompilerGeneratedElement(Element generatedBy, int index) {
canCreateCompilerGeneratedElement(generatedBy, index)
}
/**
* Gets the index of the first explicitly initialized element in `initList`

View File

@@ -9,8 +9,11 @@ private import TranslatedDeclaration
private import TranslatedElement
private import TranslatedFunction
private import TranslatedInitialization
private import TranslatedFunction
private import TranslatedStmt
private import common.TranslatedConditionBase
private import common.TranslatedCallBase
private import common.TranslatedExprBase
private import desugar.Delegate
private import desugar.internal.TranslatedCompilerGeneratedCall
import TranslatedCall
private import semmle.code.csharp.ir.Util
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
@@ -35,14 +38,9 @@ TranslatedExpr getTranslatedExpr(Expr expr) {
* as the `TranslatedAllocatorCall` and `TranslatedAllocationSize` within the
* translation of a `NewExpr`.
*/
abstract class TranslatedExpr extends TranslatedElement {
abstract class TranslatedExpr extends TranslatedExprBase {
Expr expr;
/**
* Gets the instruction that produces the result of the expression.
*/
abstract Instruction getResult();
/**
* Holds if this `TranslatedExpr` produces the final result of the original
* expression from the AST.
@@ -243,12 +241,12 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
override Instruction getChildTrueSuccessor(ConditionBase child) {
child = this.getCondition() and
result = this.getInstruction(ConditionValueTrueTempAddressTag())
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
override Instruction getChildFalseSuccessor(ConditionBase child) {
child = this.getCondition() and
result = this.getInstruction(ConditionValueFalseTempAddressTag())
}
@@ -1452,13 +1450,13 @@ class TranslatedAssignOperation extends TranslatedAssignment {
/**
* Abstract class implemented by any `TranslatedElement` that has a child
* expression that is a call to a constructor or destructor, in order to
* provide a pointer to the object being constructed or destroyed.
* expression that is a call to a constructor, in order to
* provide a pointer to the object being constructed.
*/
abstract class StructorCallContext extends TranslatedElement {
abstract class ConstructorCallContext extends TranslatedElement {
/**
* Gets the instruction whose result value is the address of the object to be
* constructed or destroyed.
* constructed.
*/
abstract Instruction getReceiver();
}
@@ -1609,12 +1607,12 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
)
}
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
override Instruction getChildTrueSuccessor(ConditionBase child) {
child = this.getCondition() and
result = this.getThen().getFirstInstruction()
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
override Instruction getChildFalseSuccessor(ConditionBase child) {
child = this.getCondition() and
result = this.getElse().getFirstInstruction()
}
@@ -1884,3 +1882,39 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont
result = getTranslatedInitialization(expr.getChild(0))
}
}
/**
* The translation of a `DelegateCall`. Since this type of call needs
* desugaring, we treat it as a special case. The AST node of the
* call expression will be the parent to a compiler generated call.
*/
class TranslatedDelegateCall extends TranslatedNonConstantExpr {
override DelegateCall expr;
final override Instruction getFirstInstruction() {
result = this.getInvokeCall().getFirstInstruction()
}
final override TranslatedElement getChild(int id) { id = 0 and result = this.getInvokeCall() }
override Instruction getResult() { result = this.getInvokeCall().getResult() }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getInvokeCall() and
result = getParent().getChildSuccessor(this)
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
none()
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() }
private TranslatedCompilerGeneratedCall getInvokeCall() {
result = DelegateElements::getInvoke(expr)
}
}

View File

@@ -165,7 +165,7 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
isLValue = false and
(
// Only generate the `Unwind` instruction if there is any exception
// handling present in the function.
// handling present in the function (compiler generated or not).
exists(TryStmt try | try.getEnclosingCallable() = callable) or
exists(ThrowStmt throw | throw.getEnclosingCallable() = callable)
)

View File

@@ -12,6 +12,7 @@ private import TranslatedExpr
private import TranslatedFunction
private import semmle.code.csharp.ir.Util
private import IRInternal
private import desugar.Delegate
/**
* Gets the `TranslatedInitialization` for the expression `expr`.
@@ -125,6 +126,7 @@ class TranslatedDirectInitialization extends TranslatedInitialization {
// TODO: Make sure this is complete and correct
not expr instanceof ArrayInitializer and
not expr instanceof ObjectInitializer and
not expr instanceof DelegateCreation and
not expr instanceof CollectionInitializer and
not expr instanceof ObjectCreation and
not expr instanceof StringLiteral
@@ -175,7 +177,7 @@ class TranslatedDirectInitialization extends TranslatedInitialization {
* object of type `expr.getType()` is allocated, which is then initialized by the
* constructor.
*/
class TranslatedObjectInitialization extends TranslatedInitialization, StructorCallContext {
class TranslatedObjectInitialization extends TranslatedInitialization, ConstructorCallContext {
override ObjectCreation expr;
override TranslatedElement getChild(int id) {
@@ -266,9 +268,9 @@ class TranslatedObjectInitialization extends TranslatedInitialization, StructorC
result = this.getInstruction(NewObjTag())
}
TranslatedExpr getConstructorCall() { result = getTranslatedExpr(expr) }
private TranslatedExpr getConstructorCall() { result = getTranslatedExpr(expr) }
TranslatedExpr getInitializerExpr() { result = getTranslatedExpr(expr.getInitializer()) }
private TranslatedExpr getInitializerExpr() { result = getTranslatedExpr(expr.getInitializer()) }
override Instruction getReceiver() {
// The newly allocated object will be the target of the constructor call
@@ -390,7 +392,7 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ
// TODO: Possibly refactor into something simpler
abstract class TranslatedConstructorCallFromConstructor extends TranslatedElement,
StructorCallContext {
ConstructorCallContext {
Call call;
final override Language::AST getAST() { result = call }
@@ -470,3 +472,58 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons
derivedClass = this.getFunction().getDeclaringType()
}
}
/**
* Represents the IR translation of a delegate creation.
*/
class TranslatedDelegateCreation extends TranslatedInitialization, ConstructorCallContext {
override DelegateCreation expr;
override TranslatedElement getChild(int id) { id = 0 and result = getConstructorCall() }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = NewObjTag() and
opcode instanceof Opcode::NewObj and
resultType = expr.getType() and
isLValue = false
or
tag = InitializerStoreTag() and
opcode instanceof Opcode::Store and
resultType = expr.getType() and
isLValue = false
}
final override Instruction getFirstInstruction() { result = getInstruction(NewObjTag()) }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = NewObjTag() and
result = getConstructorCall().getFirstInstruction() and
kind instanceof GotoEdge
or
tag = InitializerStoreTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getConstructorCall() and
result = getInstruction(InitializerStoreTag())
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = InitializerStoreTag() and
(
operandTag instanceof AddressOperandTag and
result = getParent().(InitializationContext).getTargetAddress()
or
operandTag instanceof StoreValueOperandTag and
result = getInstruction(NewObjTag())
)
}
private TranslatedElement getConstructorCall() { result = DelegateElements::getConstructor(expr) }
override Instruction getReceiver() { result = getInstruction(NewObjTag()) }
}

View File

@@ -8,8 +8,11 @@ private import TranslatedElement
private import TranslatedExpr
private import TranslatedFunction
private import TranslatedInitialization
private import common.TranslatedConditionBase
private import IRInternal
private import semmle.code.csharp.ir.internal.IRUtilities
private import desugar.Foreach
private import desugar.Lock
TranslatedStmt getTranslatedStmt(Stmt stmt) { result.getAST() = stmt }
@@ -562,12 +565,12 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
override Instruction getChildTrueSuccessor(ConditionBase child) {
child = this.getCondition() and
result = this.getThen().getFirstInstruction()
}
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
override Instruction getChildFalseSuccessor(ConditionBase child) {
child = this.getCondition() and
if this.hasElse()
then result = this.getElse().getFirstInstruction()
@@ -615,11 +618,11 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
final override Instruction getChildTrueSuccessor(ConditionBase child) {
child = this.getCondition() and result = this.getBody().getFirstInstruction()
}
final override Instruction getChildFalseSuccessor(TranslatedCondition child) {
final override Instruction getChildFalseSuccessor(ConditionBase child) {
child = this.getCondition() and result = this.getParent().getChildSuccessor(this)
}
}
@@ -848,3 +851,68 @@ class TranslatedSwitchStmt extends TranslatedStmt {
)
}
}
class TranslatedEnumeratorForeach extends TranslatedLoop {
override ForeachStmt stmt;
override TranslatedElement getChild(int id) {
id = 0 and result = getTempEnumDecl()
or
id = 1 and result = getTry()
}
override Instruction getFirstInstruction() { result = getTempEnumDecl().getFirstInstruction() }
override Instruction getChildSuccessor(TranslatedElement child) {
child = getTempEnumDecl() and
result = getTry().getFirstInstruction()
or
child = getTry() and
result = getParent().getChildSuccessor(this)
}
private TranslatedElement getTry() { result = ForeachElements::getTry(stmt) }
private TranslatedElement getTempEnumDecl() { result = ForeachElements::getEnumDecl(stmt) }
}
class TranslatedLockStmt extends TranslatedStmt {
override LockStmt stmt;
override TranslatedElement getChild(int id) {
id = 0 and result = getLockedVarDecl()
or
id = 1 and result = getLockWasTakenDecl()
or
id = 2 and result = getTry()
}
override Instruction getFirstInstruction() { result = getLockedVarDecl().getFirstInstruction() }
override Instruction getChildSuccessor(TranslatedElement child) {
child = getLockedVarDecl() and
result = getLockWasTakenDecl().getFirstInstruction()
or
child = getLockWasTakenDecl() and
result = getTry().getFirstInstruction()
or
child = getTry() and
result = getParent().getChildSuccessor(this)
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
none()
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
private TranslatedElement getTry() { result = LockElements::getTry(stmt) }
private TranslatedElement getLockedVarDecl() { result = LockElements::getLockedVarDecl(stmt) }
private TranslatedElement getLockWasTakenDecl() {
result = LockElements::getLockWasTakenDecl(stmt)
}
}

View File

@@ -0,0 +1,219 @@
/**
* Contains an abstract class that serves as a Base for classes that deal with the translation of calls
* (both AST generated and compiler generated).
*/
import csharp
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.csharp.ir.Util
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
private import TranslatedExprBase
abstract class TranslatedCallBase extends TranslatedElement {
override final TranslatedElement getChild(int id) {
// We choose the child's id in the order of evaluation.
// Note: some calls do need qualifiers, though instructions for them have already
// been generated; eg. a constructor does not need to generate a qualifier,
// though the `this` argument exists and is the result of the instruction
// that allocated the new object. For those calls, `getQualifier()` should
// be void.
id = -1 and result = getQualifier() or
result = getArgument(id)
}
override final Instruction getFirstInstruction() {
if exists(getQualifier()) then
result = getQualifier().getFirstInstruction()
else
result = getInstruction(CallTargetTag())
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
(
tag = CallTag() and
opcode instanceof Opcode::Call and
resultType = getCallResultType() and
isLValue = false
) or
(
hasSideEffect() and
tag = CallSideEffectTag() and
(
if hasWriteSideEffect() then (
opcode instanceof Opcode::CallSideEffect and
resultType instanceof Language::UnknownType
)
else (
opcode instanceof Opcode::CallReadSideEffect and
resultType instanceof Language::UnknownType
)
) and
isLValue = false
) or
(
tag = CallTargetTag() and
opcode instanceof Opcode::FunctionAddress and
// Since the DB does not have a function type,
// we just use the UnknownType
resultType instanceof Language::UnknownType and
isLValue = true
)
}
override Instruction getChildSuccessor(TranslatedElement child) {
(
child = getQualifier() and
result = getInstruction(CallTargetTag())
) or
exists(int argIndex |
child = getArgument(argIndex) and
if exists(getArgument(argIndex + 1)) then
result = getArgument(argIndex + 1).getFirstInstruction()
else
result = getInstruction(CallTag())
)
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
kind instanceof GotoEdge and
(
(
tag = CallTag() and
if hasSideEffect() then
result = getInstruction(CallSideEffectTag())
else
result = getParent().getChildSuccessor(this)
) or
(
hasSideEffect() and
tag = CallSideEffectTag() and
result = getParent().getChildSuccessor(this)
) or
(
tag = CallTargetTag() and
kind instanceof GotoEdge and
result = getFirstArgumentOrCallInstruction()
)
)
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
(
tag = CallTag() and
(
(
operandTag instanceof CallTargetOperandTag and
result = getInstruction(CallTargetTag())
) or
(
operandTag instanceof ThisArgumentOperandTag and
result = getQualifierResult()
) or
exists(PositionalArgumentOperandTag argTag |
argTag = operandTag and
result = getArgument(argTag.getArgIndex()).getResult()
)
)
) or
(
tag = CallSideEffectTag() and
hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result = getUnmodeledDefinitionInstruction()
)
}
override final Type getInstructionOperandType(InstructionTag tag,
TypedOperandTag operandTag) {
tag = CallSideEffectTag() and
hasSideEffect() and
operandTag instanceof SideEffectOperandTag and
result instanceof Language::UnknownType
}
Instruction getResult() {
result = getInstruction(CallTag())
}
/**
* Gets the result type of the call.
*/
abstract Type getCallResultType();
/**
* Gets the unmodeled definition instruction of the enclosing
* function (of the element this call is attached to).
*/
abstract Instruction getUnmodeledDefinitionInstruction();
/**
* Holds if the call has a `this` argument.
*/
predicate hasQualifier() {
exists(getQualifier())
}
/**
* Gets the expr for the qualifier of the call.
*/
abstract TranslatedExprBase getQualifier();
/**
* Gets the instruction whose result value is the `this` argument of the call.
* In general, this is just the result of `getQualifier()`, but it can be
* overridden by a subclass for cases where there is a `this` argument that is
* not computed from a child expression (e.g. a constructor call).
*/
abstract Instruction getQualifierResult();
/**
* Gets the argument with the specified `index`. Does not include the `this`
* argument. We use `TranslatedExprBase` so that we can give both `TranslatedExpr` args,
* in the case of AST generated arguments, or `TranslatedCompilerElement` args in the case of
* compiler generated arguments.
*/
abstract TranslatedExprBase getArgument(int index);
/**
* If there are any arguments, gets the first instruction of the first
* argument. Otherwise, returns the call instruction.
*/
final Instruction getFirstArgumentOrCallInstruction() {
if hasArguments() then
result = getArgument(0).getFirstInstruction()
else
result = getInstruction(CallTag())
}
/**
* Holds if the call has any arguments, not counting the `this` argument.
*/
final predicate hasArguments() {
exists(getArgument(0))
}
predicate hasReadSideEffect() {
any()
}
predicate hasWriteSideEffect() {
any()
}
private predicate hasSideEffect() {
hasReadSideEffect() or hasWriteSideEffect()
}
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
hasSideEffect() and
tag = CallSideEffectTag() and
result = getResult()
}
}

View File

@@ -0,0 +1,92 @@
/**
* Contains several abstract classes that serve as Bases.
*/
import csharp
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
/**
* Represents the context of the condition, ie. provides
* information about the instruction that follows a conditional branch.
*/
abstract class ConditionContext extends TranslatedElement {
abstract Instruction getChildTrueSuccessor(ConditionBase child);
abstract Instruction getChildFalseSuccessor(ConditionBase child);
}
/**
* Abstract class that serves as a Base for the classes that deal with both the AST generated conditions
* and the compiler generated ones (captures the common patterns).
*/
abstract class ConditionBase extends TranslatedElement {
final ConditionContext getConditionContext() {
result = getParent()
}
}
/**
* Abstract class that serves as a Base for the classes that deal with both the AST generated _value_ conditions
* and the compiler generated ones (captures the common patterns).
*/
abstract class ValueConditionBase extends ConditionBase {
override TranslatedElement getChild(int id) {
id = 0 and result = getValueExpr()
}
override Instruction getFirstInstruction() {
result = getValueExpr().getFirstInstruction()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
tag = ValueConditionConditionalBranchTag() and
opcode instanceof Opcode::ConditionalBranch and
resultType instanceof VoidType and
isLValue = false
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getValueExpr() and
result = getInstruction(ValueConditionConditionalBranchTag())
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
tag = ValueConditionConditionalBranchTag() and
(
(
kind instanceof TrueEdge and
result = getConditionContext().getChildTrueSuccessor(this)
) or
(
kind instanceof FalseEdge and
result = getConditionContext().getChildFalseSuccessor(this)
)
)
}
override Instruction getInstructionOperand(InstructionTag tag,
OperandTag operandTag) {
tag = ValueConditionConditionalBranchTag() and
operandTag instanceof ConditionOperandTag and
result = valueExprResult()
}
/**
* Gets the instruction that represents the result of the value expression.
*/
abstract Instruction valueExprResult();
/**
* Gets the `TranslatedElements that represents the value expression.
*/
abstract TranslatedElement getValueExpr();
}

View File

@@ -0,0 +1,120 @@
/**
* Contains an abstract class that serves as a Base for the classes that deal with both the AST
* generated declarations and the compiler generated ones (captures the common patterns).
*/
import csharp
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.internal.IRUtilities
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedInitialization
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class LocalVariableDeclarationBase extends TranslatedElement {
override TranslatedElement getChild(int id) {
id = 0 and result = getInitialization()
}
override Instruction getFirstInstruction() {
result = getVarAddress()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
Type resultType, boolean isLValue) {
(
tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = getVarType() and
isLValue = true
) or
(
hasUninitializedInstruction() and
tag = InitializerStoreTag() and
opcode instanceof Opcode::Uninitialized and
resultType = getVarType() and
isLValue = false
)
}
override Instruction getInstructionSuccessor(InstructionTag tag,
EdgeKind kind) {
(
tag = InitializerVariableAddressTag() and
kind instanceof GotoEdge and
if hasUninitializedInstruction() then
result = getInstruction(InitializerStoreTag())
else
if isInitializedByElement() then
// initialization is done by an element
result = getParent().getChildSuccessor(this)
else
result = getInitialization().getFirstInstruction()
) or
(
hasUninitializedInstruction() and
kind instanceof GotoEdge and
tag = InitializerStoreTag() and
(
result = getInitialization().getFirstInstruction() or
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
)
)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getInitialization() and result = getParent().getChildSuccessor(this)
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
hasUninitializedInstruction() and
tag = InitializerStoreTag() and
operandTag instanceof AddressOperandTag and
result = getVarAddress()
}
/**
* Holds if the declaration should have an `Uninitialized` instruction.
* Compiler generated elements should override this predicate and
* make it empty, since we always initialize the vars declared during the
* desugaring process.
*/
predicate hasUninitializedInstruction() {
(
not exists(getInitialization()) or
getInitialization() instanceof TranslatedListInitialization
) and
not isInitializedByElement()
}
Instruction getVarAddress() {
result = getInstruction(InitializerVariableAddressTag())
}
/**
* Gets the declared variable. For compiler generated elements, this
* should be empty (since we treat temp vars differently).
*/
abstract LocalVariable getDeclVar();
/**
* Gets the type of the declared variable.
*/
abstract Type getVarType();
/**
* Gets the initialization, if there is one.
* For compiler generated elements we don't treat the initialization
* as a different step, but do it during the declaration.
*/
abstract TranslatedElement getInitialization();
/**
* Holds if a declaration is not explicitly initialized,
* but will be implicitly initialized by an element.
*/
abstract predicate isInitializedByElement();
}

View File

@@ -0,0 +1,14 @@
/**
* Contains an abstract class that serves as a Base for classes that deal with the translation of exprs
* (both AST generated and compiler generated).
*/
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class TranslatedExprBase extends TranslatedElement {
/**
* Gets the instruction that produces the result of the expression.
*/
abstract Instruction getResult();
}

View File

@@ -0,0 +1,245 @@
/**
* Exposes several patterns for the compiler generated code, so as to improve code sharing between files that
* deal with the desugaring process.
* For example, we expose the `try ... finally` pattern, which is shared by the desugaring of both the
* `ForeachStmt`, `UsingStmt` and `LockStmt`.
*/
import csharp
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.internal.TempVariableTag
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction
private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag
private import internal.TranslatedCompilerGeneratedStmt
private import internal.TranslatedCompilerGeneratedExpr
private import internal.TranslatedCompilerGeneratedCondition
private import internal.TranslatedCompilerGeneratedCall
private import internal.TranslatedCompilerGeneratedElement
private import internal.TranslatedCompilerGeneratedDeclaration
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
/**
* The general form of a compiler generated try stmt.
* The concrete implementation needs to specify the body of the try and the
* finally block.
*/
abstract class TranslatedCompilerGeneratedTry extends TranslatedCompilerGeneratedStmt {
override Stmt generatedBy;
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
none()
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override TranslatedElement getChild(int id) {
id = 0 and result = getBody()
or
id = 1 and result = getFinally()
}
override Instruction getFirstInstruction() { result = getBody().getFirstInstruction() }
override Instruction getChildSuccessor(TranslatedElement child) {
child = getBody() and result = getFinally().getFirstInstruction()
or
child = getFinally() and result = getParent().getChildSuccessor(this)
}
override Instruction getExceptionSuccessorInstruction() {
result = getParent().getExceptionSuccessorInstruction()
}
/**
* Gets the finally block.
*/
abstract TranslatedElement getFinally();
/**
* Gets the body of the try stmt.
*/
abstract TranslatedElement getBody();
}
/**
* The general form of a compiler generated constant expression.
* The concrete implementation needs to specify the immediate operand that represents the constant.
*/
abstract class TranslatedCompilerGeneratedConstant extends TranslatedCompilerGeneratedExpr {
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
opcode instanceof Opcode::Constant and
tag = OnlyInstructionTag() and
resultType = getResultType() and
isLValue = false
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = OnlyInstructionTag() and
kind instanceof GotoEdge and
result = getParent().getChildSuccessor(this)
}
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
override TranslatedElement getChild(int id) { none() }
override Instruction getChildSuccessor(TranslatedElement child) { none() }
}
/**
* The general form of a compiler generated block stmt.
* The concrete implementation needs to specify the statements that
* compose the block.
*/
abstract class TranslatedCompilerGeneratedBlock extends TranslatedCompilerGeneratedStmt {
override TranslatedElement getChild(int id) { result = getStmt(id) }
override Instruction getFirstInstruction() { result = getStmt(0).getFirstInstruction() }
abstract TranslatedElement getStmt(int index);
private int getStmtCount() { result = count(getStmt(_)) }
override Instruction getChildSuccessor(TranslatedElement child) {
exists(int index |
child = getStmt(index) and
if index = (getStmtCount() - 1)
then result = getParent().getChildSuccessor(this)
else result = getStmt(index + 1).getFirstInstruction()
)
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
none()
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
}
/**
* The general form of a compiler generated if stmt.
* The concrete implementation needs to specify the condition,
* the body of the `then` and the body of the `else`.
*/
abstract class TranslatedCompilerGeneratedIfStmt extends TranslatedCompilerGeneratedStmt,
ConditionContext {
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
override TranslatedElement getChild(int id) {
id = 0 and result = getCondition()
or
id = 1 and result = getThen()
or
id = 2 and result = getElse()
}
abstract TranslatedCompilerGeneratedValueCondition getCondition();
abstract TranslatedCompilerGeneratedElement getThen();
abstract TranslatedCompilerGeneratedElement getElse();
private predicate hasElse() { exists(getElse()) }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildTrueSuccessor(ConditionBase child) {
child = getCondition() and
result = getThen().getFirstInstruction()
}
override Instruction getChildFalseSuccessor(ConditionBase child) {
child = getCondition() and
if hasElse()
then result = getElse().getFirstInstruction()
else result = getParent().getChildSuccessor(this)
}
override Instruction getChildSuccessor(TranslatedElement child) {
(child = getThen() or child = getElse()) and
result = getParent().getChildSuccessor(this)
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
none()
}
}
/**
* The general form of a compiler generated variable access.
* The concrete implementation needs to specify the immediate
* operand for the `VariableAddress` instruction and if the
* access needs a `Load` instruction or not (eg. `ref` params do not)
*/
abstract class TranslatedCompilerGeneratedVariableAccess extends TranslatedCompilerGeneratedExpr {
override Instruction getFirstInstruction() { result = getInstruction(AddressTag()) }
override TranslatedElement getChild(int id) { none() }
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = AddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = getResultType() and
isLValue = true
or
needsLoad() and
tag = LoadTag() and
opcode instanceof Opcode::Load and
resultType = getResultType() and
isLValue = false
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
needsLoad() and
tag = LoadTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
or
(
tag = AddressTag() and
kind instanceof GotoEdge and
if needsLoad()
then result = getInstruction(LoadTag())
else result = getParent().getChildSuccessor(this)
)
}
override Instruction getResult() {
if needsLoad()
then result = getInstruction(LoadTag())
else result = getInstruction(AddressTag())
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
needsLoad() and
tag = LoadTag() and
(
operandTag instanceof AddressOperandTag and
result = getInstruction(AddressTag())
or
operandTag instanceof LoadOperandTag and
result = getTranslatedFunction(getFunction()).getUnmodeledDefinitionInstruction()
)
}
/**
* Holds if the variable access should be followed by a `Load` instruction.
*/
abstract predicate needsLoad();
}

View File

@@ -0,0 +1,107 @@
/**
* File that translates the desugaring of delegate creation and call expressions.
* In particular, in the IR we explicitly allocate a new object and call the delegate's constructor when
* creating a new one.
* For the delegate call, we explicitly call the `Invoke` method.
* More information about the internals:
* https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_DelegateCreationExpression.cs
* This is a rough approximation which will need further refining.
*/
import csharp
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.internal.TempVariableTag
private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedCondition
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
private import Common
private import internal.TranslatedCompilerGeneratedCall
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase
/**
* Module that exposes the functions needed for the translation of the delegate creation and call expressions.
*/
module DelegateElements {
TranslatedDelegateConstructorCall getConstructor(DelegateCreation generatedBy) {
result.getAST() = generatedBy
}
TranslatedDelegateInvokeCall getInvoke(DelegateCall generatedBy) { result.getAST() = generatedBy }
int noGeneratedElements(Element generatedBy) {
generatedBy instanceof DelegateCreation and result = 1
or
generatedBy instanceof DelegateCall and result = 1
}
}
/**
* The translation of the constructor call that happens as part of the delegate creation.
*/
private class TranslatedDelegateConstructorCall extends TranslatedCompilerGeneratedCall,
TTranslatedCompilerGeneratedElement {
override DelegateCreation generatedBy;
TranslatedDelegateConstructorCall() { this = TTranslatedCompilerGeneratedElement(generatedBy, 0) }
final override Type getCallResultType() { result instanceof VoidType }
override TranslatedExpr getArgument(int index) {
index = 0 and result = getTranslatedExpr(generatedBy.getArgument())
}
override TranslatedExprBase getQualifier() { none() }
override Instruction getQualifierResult() {
exists(ConstructorCallContext context |
context = getParent() and
result = context.getReceiver()
)
}
override Callable getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and
exists(Callable internal |
internal.getName() = generatedBy.getDelegateType().getName() and
internal.isCompilerGenerated() and
internal.getFile() = generatedBy.getFile() and
result = internal
)
}
}
/**
* The translation of the invoke call that happens as part of the desugaring of the delegate call.
*/
private class TranslatedDelegateInvokeCall extends TranslatedCompilerGeneratedCall,
TTranslatedCompilerGeneratedElement {
override DelegateCall generatedBy;
TranslatedDelegateInvokeCall() { this = TTranslatedCompilerGeneratedElement(generatedBy, 1) }
final override Type getCallResultType() { result instanceof VoidType }
override Callable getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and
exists(Callable internal |
internal.getName() = "Invoke" and
internal.isCompilerGenerated() and
internal.getFile() = generatedBy.getFile() and
result = internal
)
}
override TranslatedExprBase getQualifier() {
result = getTranslatedExpr(generatedBy.getDelegateExpr())
}
override Instruction getQualifierResult() { result = getQualifier().getResult() }
override TranslatedExpr getArgument(int index) {
result = getTranslatedExpr(generatedBy.getArgument(index))
}
}

View File

@@ -0,0 +1,452 @@
/**
* File that provides the desugaring of a `Foreach` stmt.
* Since Roslyn rewrites it in quite a few ways,
* for now only desugar it to a "canonical" form.
* Also we only deal with foreach stmts where there is only
* one declaration (see below).
* For example the code:
* ```
* foreach(var item in some_enumerable) {
* // body
* }
* ```
* gets desugared to:
* ```
* Enumerator e = some_enumerable.GetEnumerator();
* try
* {
* while(e.MoveNext())
* {
* int current = e.Current;
* //body
* }
* }
* finally
* {
* e.Dispose();
* }
* ```
* More info about the desugaring process for `foreach` stmts:
* https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_ForEachStatement.cs
* A TODO is to not call `Dispose` no matter what, but desugar the `finally` as an `AsExpr` (cast to IDisposable),
* the call to `Dispose` being made only if the result of the `AsExpr` is not null.
* This is a rough approximation which will need further refining.
*/
import csharp
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.internal.TempVariableTag
private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
private import Common
private import internal.TranslatedCompilerGeneratedStmt
private import internal.TranslatedCompilerGeneratedCall
private import internal.TranslatedCompilerGeneratedDeclaration
private import internal.TranslatedCompilerGeneratedCondition
private import internal.TranslatedCompilerGeneratedElement
/**
* Module that exposes the functions needed for the translation of the `foreach` stmt.
*/
module ForeachElements {
TranslatedForeachTry getTry(ForeachStmt generatedBy) { result.getAST() = generatedBy }
TranslatedForeachEnumerator getEnumDecl(ForeachStmt generatedBy) { result.getAST() = generatedBy }
int noGeneratedElements() { result = 12 }
}
private class TranslatedForeachTry extends TranslatedCompilerGeneratedTry,
TTranslatedCompilerGeneratedElement {
override ForeachStmt generatedBy;
TranslatedForeachTry() { this = TTranslatedCompilerGeneratedElement(generatedBy, 0) }
override TranslatedElement getFinally() {
exists(TranslatedForeachFinally ff |
ff.getAST() = generatedBy and
result = ff
)
}
override TranslatedElement getBody() {
exists(TranslatedForeachWhile fw |
fw.getAST() = generatedBy and
result = fw
)
}
}
/**
* The translation of the finally block.
*/
private class TranslatedForeachFinally extends TranslatedCompilerGeneratedBlock,
TTranslatedCompilerGeneratedElement {
override ForeachStmt generatedBy;
TranslatedForeachFinally() { this = TTranslatedCompilerGeneratedElement(generatedBy, 1) }
override TranslatedElement getStmt(int index) {
index = 0 and
exists(TranslatedForeachDispose fd |
fd.getAST() = generatedBy and
result = fd
)
}
}
/**
* The compiler generated while loop.
* Note that this class is not private since it is needed in `IRConstruction.qll`,
* to correctly mark which edges should be back edges.
*/
class TranslatedForeachWhile extends TranslatedCompilerGeneratedStmt, ConditionContext,
TTranslatedCompilerGeneratedElement {
override ForeachStmt generatedBy;
TranslatedForeachWhile() { this = TTranslatedCompilerGeneratedElement(generatedBy, 2) }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
none()
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
override Instruction getChildSuccessor(TranslatedElement child) {
child = getInit() and result = getBody().getFirstInstruction()
or
child = getBody() and result = getCondition().getFirstInstruction()
}
override TranslatedElement getChild(int id) {
id = 0 and result = getCondition()
or
id = 1 and result = getInit()
or
id = 2 and result = getBody()
}
final override Instruction getChildTrueSuccessor(ConditionBase child) {
child = getCondition() and result = getInit().getFirstInstruction()
}
final override Instruction getChildFalseSuccessor(ConditionBase child) {
child = getCondition() and result = getParent().getChildSuccessor(this)
}
TranslatedStmt getBody() { result = getTranslatedStmt(generatedBy.getBody()) }
TranslatedElement getInit() {
exists(TranslatedForeachIterVar iv |
iv.getAST() = generatedBy and
result = iv
)
}
ValueConditionBase getCondition() {
exists(TranslatedForeachWhileCondition cond |
cond.getAST() = generatedBy and
result = cond
)
}
}
/**
* The translation of the call to the `MoveNext` method, used as a condition for the while.
*/
private class TranslatedForeachMoveNext extends TranslatedCompilerGeneratedCall,
TTranslatedCompilerGeneratedElement {
override ForeachStmt generatedBy;
TranslatedForeachMoveNext() { this = TTranslatedCompilerGeneratedElement(generatedBy, 3) }
override Callable getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and
exists(Callable internal |
internal.getName() = "MoveNext" and
internal.getReturnType() instanceof BoolType and
result = internal
)
}
override Type getCallResultType() { result instanceof BoolType }
override TranslatedExpr getArgument(int id) { none() }
override TranslatedExprBase getQualifier() {
exists(TranslatedMoveNextEnumAcc acc |
acc.getAST() = generatedBy and
result = acc
)
}
override Instruction getQualifierResult() { result = getQualifier().getResult() }
}
/**
* The translation of the call to retrieve the enumerator.
*/
private class TranslatedForeachGetEnumerator extends TranslatedCompilerGeneratedCall,
TTranslatedCompilerGeneratedElement {
override ForeachStmt generatedBy;
TranslatedForeachGetEnumerator() { this = TTranslatedCompilerGeneratedElement(generatedBy, 4) }
final override Type getCallResultType() {
result = getInstructionFunction(CallTargetTag()).getReturnType()
}
private Callable getEnumeratorCallable() {
if exists(generatedBy.getIterableExpr().getType().(ValueOrRefType).getAMember("GetEnumerator"))
then
result = generatedBy.getIterableExpr().getType().(ValueOrRefType).getAMember("GetEnumerator")
else
exists(Interface inter |
inter = generatedBy
.getIterableExpr()
.getType()
.(ValueOrRefType)
// There could be some abstract base types until we reach `IEnumerable` (eg. `Array`)
.getABaseType*()
.getABaseInterface() and
inter.getName() = "IEnumerable" and
result = inter.getAMember("GetEnumerator")
)
}
override Callable getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and
result = getEnumeratorCallable()
}
override TranslatedExpr getArgument(int id) { none() }
override TranslatedExprBase getQualifier() {
result = getTranslatedExpr(generatedBy.getIterableExpr())
}
override Instruction getQualifierResult() { result = getQualifier().getResult() }
}
/**
* The translation of the call to the getter method of the `Current` property of the enumerator.
*/
private class TranslatedForeachCurrent extends TranslatedCompilerGeneratedCall,
TTranslatedCompilerGeneratedElement {
override ForeachStmt generatedBy;
TranslatedForeachCurrent() { this = TTranslatedCompilerGeneratedElement(generatedBy, 5) }
override Type getCallResultType() { result = generatedBy.getAVariable().getType() }
override TranslatedExpr getArgument(int id) { none() }
override TranslatedExprBase getQualifier() {
exists(TranslatedForeachCurrentEnumAcc acc |
acc.getAST() = generatedBy and
result = acc
)
}
override Instruction getQualifierResult() { result = getQualifier().getResult() }
override Callable getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and
exists(Property prop |
prop.getName() = "Current" and
result = prop.getGetter()
)
}
}
/**
* The translation of the call to dispose (inside the finally block)
*/
private class TranslatedForeachDispose extends TranslatedCompilerGeneratedCall,
TTranslatedCompilerGeneratedElement {
override ForeachStmt generatedBy;
TranslatedForeachDispose() { this = TTranslatedCompilerGeneratedElement(generatedBy, 6) }
override Callable getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and
exists(Callable dispose |
dispose.getName() = "Dispose" and
result = dispose
)
}
final override Type getCallResultType() { result instanceof VoidType }
override TranslatedExpr getArgument(int id) { none() }
override TranslatedExprBase getQualifier() {
exists(TranslatedForeachDisposeEnumAcc acc |
acc.getAST() = generatedBy and
result = acc
)
}
override Instruction getQualifierResult() { result = getQualifier().getResult() }
}
/**
* The condition for the while, ie. a call to MoveNext.
*/
private class TranslatedForeachWhileCondition extends TranslatedCompilerGeneratedValueCondition,
TTranslatedCompilerGeneratedElement {
override ForeachStmt generatedBy;
TranslatedForeachWhileCondition() { this = TTranslatedCompilerGeneratedElement(generatedBy, 7) }
override TranslatedCompilerGeneratedCall getValueExpr() {
exists(TranslatedForeachMoveNext mn |
mn.getAST() = generatedBy and
result = mn
)
}
override Instruction valueExprResult() { result = getValueExpr().getResult() }
}
/**
* Class that represents that translation of the declaration that happens before the `try ... finally` block (the
* declaration of the `temporary` enumerator variable)
*/
private class TranslatedForeachEnumerator extends TranslatedCompilerGeneratedDeclaration,
TTranslatedCompilerGeneratedElement {
override ForeachStmt generatedBy;
TranslatedForeachEnumerator() { this = TTranslatedCompilerGeneratedElement(generatedBy, 8) }
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = ForeachEnumTempVar() and
type = getInitialization().getCallResultType()
}
override IRTempVariable getIRVariable() {
result = getIRTempVariable(generatedBy, ForeachEnumTempVar())
}
override TranslatedCompilerGeneratedCall getInitialization() {
exists(TranslatedForeachGetEnumerator ge |
ge.getAST() = generatedBy and
result = ge
)
}
override Instruction getInitializationResult() { result = getInitialization().getResult() }
}
/**
* Class that represents that translation of the declaration that's happening inside the body of the while.
*/
private class TranslatedForeachIterVar extends TranslatedCompilerGeneratedDeclaration,
TTranslatedCompilerGeneratedElement {
override ForeachStmt generatedBy;
TranslatedForeachIterVar() { this = TTranslatedCompilerGeneratedElement(generatedBy, 9) }
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = InitializerVariableAddressTag() and
result = getIRVariable()
}
override IRVariable getIRVariable() {
result = getIRUserVariable(getFunction(), generatedBy.getAVariable())
}
override TranslatedCompilerGeneratedCall getInitialization() {
exists(TranslatedForeachCurrent crtProp |
crtProp.getAST() = generatedBy and
result = crtProp
)
}
override Instruction getInitializationResult() { result = getInitialization().getResult() }
}
/**
* Class that represents that translation of access to the temporary enumerator variable. Used as the qualifier
* for the call to `MoveNext`.
*/
private class TranslatedMoveNextEnumAcc extends TTranslatedCompilerGeneratedElement,
TranslatedCompilerGeneratedVariableAccess {
override ForeachStmt generatedBy;
TranslatedMoveNextEnumAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 10) }
override Type getResultType() { result instanceof BoolType }
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = ForeachEnumTempVar() and
type = getResultType()
}
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = AddressTag() and
result = getTempVariable(ForeachEnumTempVar())
}
override predicate needsLoad() { any() }
}
/**
* Class that represents that translation of access to the temporary enumerator variable. Used as the qualifier
* for the call to the getter of the property `Current`.
*/
private class TranslatedForeachCurrentEnumAcc extends TTranslatedCompilerGeneratedElement,
TranslatedCompilerGeneratedVariableAccess {
override ForeachStmt generatedBy;
TranslatedForeachCurrentEnumAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 11) }
override Type getResultType() { result instanceof BoolType }
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = ForeachEnumTempVar() and
type = getResultType()
}
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = AddressTag() and
result = getTempVariable(ForeachEnumTempVar())
}
override predicate needsLoad() { any() }
}
/**
* Class that represents that translation of access to the temporary enumerator variable. Used as the qualifier
* for the call to `Dispose`.
*/
private class TranslatedForeachDisposeEnumAcc extends TTranslatedCompilerGeneratedElement,
TranslatedCompilerGeneratedVariableAccess {
override ForeachStmt generatedBy;
TranslatedForeachDisposeEnumAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 12) }
override Type getResultType() { result instanceof BoolType }
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = ForeachEnumTempVar() and
type = getResultType()
}
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = AddressTag() and
result = getTempVariable(ForeachEnumTempVar())
}
override predicate needsLoad() { any() }
}

View File

@@ -0,0 +1,411 @@
/**
* File that provides the desugaring of a `lock` stmt.
* The statement:
* ```
* lock (anExpr) ...
* ```
* gets desugared to:
* ```
* SomeRefType lockedVar = anExpr;
* bool __lockWasTaken = false;
* try {
* System.Threading.Monitor.Enter(lockedVar, ref __lockWasTaken);
* ...
* }
* finally {
* if (__lockWasTaken) System.Threading.Monitor.Exit(lockedVar);
* }
* ```
*/
import csharp
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.internal.TempVariableTag
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedExpr
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedStmt
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase
private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
private import Common
private import internal.TranslatedCompilerGeneratedStmt
private import internal.TranslatedCompilerGeneratedCall
private import internal.TranslatedCompilerGeneratedDeclaration
private import internal.TranslatedCompilerGeneratedCondition
private import internal.TranslatedCompilerGeneratedElement
private import internal.TranslatedCompilerGeneratedExpr
/**
* Module that exposes the functions needed for the translation of the `lock` stmt.
*/
module LockElements {
TranslatedLockedVarDecl getLockedVarDecl(LockStmt generatedBy) { result.getAST() = generatedBy }
TranslatedLockTry getTry(LockStmt generatedBy) { result.getAST() = generatedBy }
TranslatedLockWasTakenDecl getLockWasTakenDecl(LockStmt generatedBy) {
result.getAST() = generatedBy
}
int noGeneratedElements() { result = 13 }
}
/**
* The translation of the `try` stmt.
*/
private class TranslatedLockTry extends TranslatedCompilerGeneratedTry,
TTranslatedCompilerGeneratedElement {
override LockStmt generatedBy;
TranslatedLockTry() { this = TTranslatedCompilerGeneratedElement(generatedBy, 0) }
override TranslatedElement getFinally() {
exists(TranslatedLockFinally fin |
fin.getAST() = generatedBy and
result = fin
)
}
override TranslatedElement getBody() {
exists(TranslatedLockTryBody ltb |
ltb.getAST() = generatedBy and
result = ltb
)
}
}
/**
* The translation of the `lock` stmt's body.
*/
private class TranslatedLockTryBody extends TranslatedCompilerGeneratedBlock,
TTranslatedCompilerGeneratedElement {
override LockStmt generatedBy;
TranslatedLockTryBody() { this = TTranslatedCompilerGeneratedElement(generatedBy, 1) }
override TranslatedElement getStmt(int index) {
index = 0 and
exists(TranslatedMonitorEnter me |
me.getAST() = generatedBy and
result = me
)
or
index = 1 and
result = getTranslatedStmt(generatedBy.getBlock())
}
}
/**
* The translation of the finally block.
*/
private class TranslatedLockFinally extends TranslatedCompilerGeneratedBlock,
TTranslatedCompilerGeneratedElement {
override LockStmt generatedBy;
TranslatedLockFinally() { this = TTranslatedCompilerGeneratedElement(generatedBy, 2) }
override TranslatedElement getStmt(int index) {
index = 0 and
exists(TranslatedFinallyIf fif |
fif.getAST() = generatedBy and
result = fif
)
}
}
/**
* The translation of the call to dispose (inside the finally block)
*/
private class TranslatedMonitorExit extends TranslatedCompilerGeneratedCall,
TTranslatedCompilerGeneratedElement {
override LockStmt generatedBy;
TranslatedMonitorExit() { this = TTranslatedCompilerGeneratedElement(generatedBy, 3) }
override Callable getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and
exists(Callable exit |
exit.getQualifiedName() = "System.Threading.Monitor.Exit" and
result = exit
)
}
final override Type getCallResultType() { result instanceof VoidType }
override TranslatedExprBase getArgument(int id) {
id = 0 and
exists(TranslatedMonitorExitVarAcc var |
var.getAST() = generatedBy and
result = var
)
}
override TranslatedExprBase getQualifier() { none() }
override Instruction getQualifierResult() { none() }
}
/**
* The translation of the call to dispose (inside the finally block)
*/
private class TranslatedMonitorEnter extends TranslatedCompilerGeneratedCall,
TTranslatedCompilerGeneratedElement {
override LockStmt generatedBy;
TranslatedMonitorEnter() { this = TTranslatedCompilerGeneratedElement(generatedBy, 4) }
override Callable getInstructionFunction(InstructionTag tag) {
tag = CallTargetTag() and
exists(Callable dispose |
dispose.getQualifiedName() = "System.Threading.Monitor.Enter" and
result = dispose
)
}
final override Type getCallResultType() { result instanceof VoidType }
override TranslatedExprBase getArgument(int id) {
id = 0 and
exists(TranslatedMonitorEnterVarAcc var |
var.getAST() = generatedBy and
result = var
)
or
id = 1 and
exists(TranslatedLockWasTakenRefArg refArg |
refArg.getAST() = generatedBy and
result = refArg
)
}
override TranslatedExprBase getQualifier() { none() }
override Instruction getQualifierResult() { none() }
}
/**
* The translation of the condition of the `if` present in the `finally` clause.
*/
private class TranslatedIfCondition extends TranslatedCompilerGeneratedValueCondition,
TTranslatedCompilerGeneratedElement {
override LockStmt generatedBy;
TranslatedIfCondition() { this = TTranslatedCompilerGeneratedElement(generatedBy, 5) }
override TranslatedCompilerGeneratedExpr getValueExpr() {
exists(TranslatedLockWasTakenCondVarAcc condVar |
condVar.getAST() = generatedBy and
result = condVar
)
}
override Instruction valueExprResult() { result = getValueExpr().getResult() }
}
/**
* The translation of the `if` stmt present in the `finally` clause.
*/
private class TranslatedFinallyIf extends TranslatedCompilerGeneratedIfStmt,
TTranslatedCompilerGeneratedElement {
override LockStmt generatedBy;
TranslatedFinallyIf() { this = TTranslatedCompilerGeneratedElement(generatedBy, 6) }
override TranslatedCompilerGeneratedValueCondition getCondition() {
exists(TranslatedIfCondition cond |
cond.getAST() = generatedBy and
result = cond
)
}
override TranslatedCompilerGeneratedCall getThen() {
exists(TranslatedMonitorExit me |
me.getAST() = generatedBy and
result = me
)
}
override TranslatedCompilerGeneratedCall getElse() { none() }
}
/**
* Represents the translation of the constant that is part of the initialization for the
* bool temp variable.
*/
private class TranslatedWasTakenConst extends TranslatedCompilerGeneratedConstant,
TTranslatedCompilerGeneratedElement {
override LockStmt generatedBy;
TranslatedWasTakenConst() { this = TTranslatedCompilerGeneratedElement(generatedBy, 7) }
override string getInstructionConstantValue(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = "false"
}
override Instruction getResult() { result = getInstruction(OnlyInstructionTag()) }
override Type getResultType() { result instanceof BoolType }
}
/**
* Represents the translation of the `lockWasTaken` temp variable declaration.
*/
private class TranslatedLockWasTakenDecl extends TranslatedCompilerGeneratedDeclaration,
TTranslatedCompilerGeneratedElement {
override LockStmt generatedBy;
TranslatedLockWasTakenDecl() { this = TTranslatedCompilerGeneratedElement(generatedBy, 8) }
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = LockWasTakenTemp() and
type instanceof BoolType
}
override IRTempVariable getIRVariable() {
result = getIRTempVariable(generatedBy, LockWasTakenTemp())
}
override TranslatedCompilerGeneratedExpr getInitialization() {
exists(TranslatedWasTakenConst const |
const.getAST() = generatedBy and
result = const
)
}
override Type getVarType() { result = getInitialization().getResultType() }
override Instruction getInitializationResult() { result = getInitialization().getResult() }
}
/**
* Represents the translation of the declaration of the temp variable that is initialized to the
* expression being locked.
*/
private class TranslatedLockedVarDecl extends TranslatedCompilerGeneratedDeclaration,
TTranslatedCompilerGeneratedElement {
override LockStmt generatedBy;
TranslatedLockedVarDecl() { this = TTranslatedCompilerGeneratedElement(generatedBy, 9) }
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = LockedVarTemp() and
type = generatedBy.getExpr().getType()
}
override IRTempVariable getIRVariable() {
result = getIRTempVariable(generatedBy, LockedVarTemp())
}
override TranslatedExprBase getInitialization() {
result = getTranslatedExpr(generatedBy.getExpr())
}
override Type getVarType() { result = generatedBy.getExpr().getType() }
override Instruction getInitializationResult() { result = getInitialization().getResult() }
}
/**
* Represents the translation of access to the temp variable that is initialized to the
* expression being locked.
* Used as an argument for the `MonitorEnter` call.
*/
private class TranslatedMonitorEnterVarAcc extends TTranslatedCompilerGeneratedElement,
TranslatedCompilerGeneratedVariableAccess {
override LockStmt generatedBy;
TranslatedMonitorEnterVarAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 10) }
override Type getResultType() { result = generatedBy.getExpr().getType() }
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = LockedVarTemp() and
type = getResultType()
}
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = AddressTag() and
result = getTempVariable(LockedVarTemp())
}
override predicate needsLoad() { any() }
}
/**
* Represents the translation of access to the temp variable that is initialized to the
* expression being locked.
* Used as an argument for the `MonitorExit` call.
*/
private class TranslatedMonitorExitVarAcc extends TTranslatedCompilerGeneratedElement,
TranslatedCompilerGeneratedVariableAccess {
override LockStmt generatedBy;
TranslatedMonitorExitVarAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 11) }
override Type getResultType() { result = generatedBy.getExpr().getType() }
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = AddressTag() and
result = getTempVariable(LockedVarTemp())
}
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = LockedVarTemp() and
type = getResultType()
}
override predicate needsLoad() { any() }
}
/**
* Represents that translation of access to the temporary bool variable.
* Used as an argument for the `MonitorEnter` call.
*/
private class TranslatedLockWasTakenCondVarAcc extends TTranslatedCompilerGeneratedElement,
TranslatedCompilerGeneratedVariableAccess {
override LockStmt generatedBy;
TranslatedLockWasTakenCondVarAcc() { this = TTranslatedCompilerGeneratedElement(generatedBy, 12) }
override Type getResultType() { result instanceof BoolType }
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = LockWasTakenTemp() and
type = getResultType()
}
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = AddressTag() and
result = getTempVariable(LockWasTakenTemp())
}
override predicate needsLoad() { any() }
}
/**
* That represents that translation of access to the temporary bool variable. Its value is used
* as the `if` condition in the finally clause.
*/
private class TranslatedLockWasTakenRefArg extends TTranslatedCompilerGeneratedElement,
TranslatedCompilerGeneratedVariableAccess {
override LockStmt generatedBy;
TranslatedLockWasTakenRefArg() { this = TTranslatedCompilerGeneratedElement(generatedBy, 13) }
override Type getResultType() { result instanceof BoolType }
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = LockWasTakenTemp() and
type = getResultType()
}
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = AddressTag() and
result = getTempVariable(LockWasTakenTemp())
}
override predicate needsLoad() { none() }
}

View File

@@ -0,0 +1,21 @@
/**
* Contains an abstract class that is the super class of the classes that deal with compiler generated calls.
*/
import csharp
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase
private import TranslatedCompilerGeneratedElement
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class TranslatedCompilerGeneratedCall extends TranslatedCallBase,
TranslatedCompilerGeneratedElement {
final override string toString() {
result = "compiler generated call (" + generatedBy.toString() + ")"
}
override Instruction getUnmodeledDefinitionInstruction() {
result = getTranslatedFunction(this.getFunction()).getUnmodeledDefinitionInstruction()
}
}

View File

@@ -0,0 +1,16 @@
/**
* Contains an abstract class that is the super class of the classes that deal with compiler generated conditions.
*/
import csharp
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBase
private import TranslatedCompilerGeneratedElement
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class TranslatedCompilerGeneratedValueCondition extends TranslatedCompilerGeneratedElement,
ValueConditionBase {
final override string toString() {
result = "compiler generated condition (" + generatedBy.toString() + ")"
}
}

View File

@@ -0,0 +1,90 @@
/**
* Contains an abstract class, which is the super class of all the classes that represent compiler
* generated declarations. It extends the Base for declarations by incorporating a `Store` instruction, since
* we treat the initialization as part of the declaration for compiler generated declarations.
*/
import csharp
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedDeclarationBase
private import TranslatedCompilerGeneratedElement
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDeclarationBase,
TranslatedCompilerGeneratedElement {
final override string toString() {
result = "compiler generated declaration (" + generatedBy.toString() + ")"
}
override TranslatedElement getChild(int id) {
result = LocalVariableDeclarationBase.super.getChild(id)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getInitialization() and result = getInstruction(InitializerStoreTag())
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
LocalVariableDeclarationBase.super.hasInstruction(opcode, tag, resultType, isLValue)
or
// we can reuse the initializer store tag
// since compiler generated declarations
// do not have the `Uninitialized` instruction
tag = InitializerStoreTag() and
opcode instanceof Opcode::Store and
resultType = getVarType() and
isLValue = false
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
result = LocalVariableDeclarationBase.super.getInstructionSuccessor(tag, kind)
or
tag = InitializerStoreTag() and
result = getParent().getChildSuccessor(this) and
kind instanceof GotoEdge
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
result = LocalVariableDeclarationBase.super.getInstructionOperand(tag, operandTag)
or
tag = InitializerStoreTag() and
(
operandTag instanceof AddressOperandTag and
result = getInstruction(InitializerVariableAddressTag())
or
operandTag instanceof StoreValueOperandTag and
result = getInitializationResult()
)
}
override IRVariable getInstructionVariable(InstructionTag tag) {
tag = InitializerVariableAddressTag() and
result = getIRVariable()
}
// A compiler generated declaration does not have an associated `LocalVariable`
// element
override LocalVariable getDeclVar() { none() }
// A compiler generated element always has an explicit
// initialization
override predicate isInitializedByElement() { none() }
override Type getVarType() { result = getIRVariable().getType() }
/**
* Gets the IR variable that corresponds to the declaration.
*/
abstract IRVariable getIRVariable();
/**
* Gets result (instruction) of the initialization expression.
*/
abstract Instruction getInitializationResult();
}

View File

@@ -0,0 +1,22 @@
/**
* The abstract super class of every `TranslatedCompilerX` class. It has one member field, `generatedBy`,
* which represents the element that generated the compiler generated element.
*/
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class TranslatedCompilerGeneratedElement extends TranslatedElement,
TTranslatedCompilerGeneratedElement {
// The element that generates generated the compiler element can
// only be a stmt or an expr
ControlFlowElement generatedBy;
override string toString() {
result = "compiler generated element (" + generatedBy.toString() + ")"
}
final override Callable getFunction() { result = generatedBy.getEnclosingCallable() }
final override Language::AST getAST() { result = generatedBy }
}

View File

@@ -0,0 +1,17 @@
/**
* Contains an abstract class, which is the super class of all the classes that represent compiler
* generated expressions.
*/
import csharp
private import TranslatedCompilerGeneratedElement
private import semmle.code.csharp.ir.implementation.raw.Instruction
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBase
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class TranslatedCompilerGeneratedExpr extends TranslatedCompilerGeneratedElement,
TranslatedExprBase {
override string toString() { result = "compiler generated expr (" + generatedBy.toString() + ")" }
abstract Type getResultType();
}

View File

@@ -0,0 +1,14 @@
/**
* Contains an abstract class, which is the super class of all the classes that represent compiler
* generated statements.
*/
import csharp
private import TranslatedCompilerGeneratedElement
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
abstract class TranslatedCompilerGeneratedStmt extends TranslatedCompilerGeneratedElement {
final override string toString() {
result = "compiler generated stmt (" + generatedBy.toString() + ")"
}
}

View File

@@ -71,6 +71,12 @@ predicate hasCaseEdge(string minValue, string maxValue) {
predicate hasPositionalArgIndex(int argIndex) {
exists(CSharp::MethodCall call | exists(call.getArgument(argIndex)))
or
// Quick fix so that generated calls (`Invoke` etc) will have the
// correct number of parameters; it is an overestimation,
// since we don't care about all the callables, so it
// should be restricted more
argIndex in [0..any(CSharp::Callable c).getNumberOfParameters() - 1]
}
predicate hasAsmOperandIndex(int operandIndex) { none() }

View File

@@ -1,16 +1,5 @@
private import csharp
/**
* Given a type, get the type that would result by applying "pointer decay".
* A function type becomes a pointer to that function type, and an array type
* becomes a pointer to the element type of the array. If the specified type
* is not subject to pointer decay, this predicate does not hold.
*/
// TODO: Only pointer to array decay in C#?
private Type getDecayedType(Type type) {
result.(PointerType).getReferentType() = type.(ArrayType).getElementType()
}
/**
* Get the actual type of the specified variable, as opposed to the declared type.
* This returns the type of the variable after any pointer decay is applied, and
@@ -21,9 +10,7 @@ Type getVariableType(Variable v) {
declaredType = v.getType() and
if v instanceof Parameter
then
result = getDecayedType(declaredType)
or
not exists(getDecayedType(declaredType)) and result = declaredType
result = declaredType
else
if declaredType instanceof ArrayType
then

View File

@@ -1,11 +1,13 @@
import csharp
// TODO: ARE THOSE TAGS ENOUGH?
newtype TTempVariableTag =
ConditionValueTempVar() or
ReturnValueTempVar() or
ThrowTempVar() or
LambdaTempVar()
LambdaTempVar() or
ForeachEnumTempVar() or
LockedVarTemp() or
LockWasTakenTemp()
string getTempVariableTagId(TTempVariableTag tag) {
tag = ConditionValueTempVar() and result = "CondVal"
@@ -15,4 +17,10 @@ string getTempVariableTagId(TTempVariableTag tag) {
tag = ThrowTempVar() and result = "Throw"
or
tag = LambdaTempVar() and result = "Lambda"
or
tag = ForeachEnumTempVar() and result = "ForeachEnum"
or
tag = LockedVarTemp() and result = "LockedVarTemp"
or
tag = LockWasTakenTemp() and result = "LockWasTakenTemp"
}

View File

@@ -0,0 +1,15 @@
using System.Collections.Generic;
public class Delegates {
delegate int Del(int num);
static int returns(int ret)
{
return ret;
}
public static void Main() {
Del del1 = new Del(returns);
del1(5);
}
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
class ForEach {
public static void Main() {
int[] a_array = new int[] { 1, 2, 3, 4, 5, 6, 7 };
foreach(int items in a_array)
{
int x = items;
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
class LockTest
{
static void A()
{
object @object = new object();
lock (@object)
{
Console.WriteLine(@object.ToString());
}
}
}

View File

@@ -143,7 +143,7 @@ casts.cs:
# 11| mu0_2(null) = UnmodeledDefinition :
# 13| r0_3(glval<Casts_A>) = VariableAddress[Aobj] :
# 13| r0_4(Casts_A) = NewObj :
# 13| r0_5(glval<Casts_A>) = FunctionAddress[Casts_A] :
# 13| r0_5(glval<null>) = FunctionAddress[Casts_A] :
# 13| v0_6(Void) = Call : func:r0_5, this:r0_4
# 13| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 13| mu0_8(Casts_A) = Store : &:r0_3, r0_4
@@ -197,7 +197,7 @@ constructor_init.cs:
# 17| mu0_2(null) = UnmodeledDefinition :
# 17| r0_3(glval<DerivedClass>) = InitializeThis :
# 17| r0_4(glval<BaseClass>) = Convert[DerivedClass : BaseClass] : r0_3
# 17| r0_5(glval<BaseClass>) = FunctionAddress[BaseClass] :
# 17| r0_5(glval<null>) = FunctionAddress[BaseClass] :
# 17| v0_6(Void) = Call : func:r0_5, this:r0_4
# 17| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 18| v0_8(Void) = NoOp :
@@ -214,7 +214,7 @@ constructor_init.cs:
# 21| r0_4(glval<Int32>) = VariableAddress[i] :
# 21| mu0_5(Int32) = InitializeParameter[i] : &:r0_4
# 21| r0_6(glval<BaseClass>) = Convert[DerivedClass : BaseClass] : r0_3
# 21| r0_7(glval<BaseClass>) = FunctionAddress[BaseClass] :
# 21| r0_7(glval<null>) = FunctionAddress[BaseClass] :
# 21| r0_8(glval<Int32>) = VariableAddress[i] :
# 21| r0_9(Int32) = Load : &:r0_8, ~mu0_2
# 21| v0_10(Void) = Call : func:r0_7, this:r0_6, 0:r0_9
@@ -234,7 +234,7 @@ constructor_init.cs:
# 25| mu0_5(Int32) = InitializeParameter[i] : &:r0_4
# 25| r0_6(glval<Int32>) = VariableAddress[j] :
# 25| mu0_7(Int32) = InitializeParameter[j] : &:r0_6
# 25| r0_8(glval<DerivedClass>) = FunctionAddress[DerivedClass] :
# 25| r0_8(glval<null>) = FunctionAddress[DerivedClass] :
# 25| r0_9(glval<Int32>) = VariableAddress[i] :
# 25| r0_10(Int32) = Load : &:r0_9, ~mu0_2
# 25| v0_11(Void) = Call : func:r0_8, this:r0_3, 0:r0_10
@@ -251,20 +251,20 @@ constructor_init.cs:
# 29| mu0_2(null) = UnmodeledDefinition :
# 31| r0_3(glval<DerivedClass>) = VariableAddress[obj1] :
# 31| r0_4(DerivedClass) = NewObj :
# 31| r0_5(glval<DerivedClass>) = FunctionAddress[DerivedClass] :
# 31| r0_5(glval<null>) = FunctionAddress[DerivedClass] :
# 31| v0_6(Void) = Call : func:r0_5, this:r0_4
# 31| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 31| mu0_8(DerivedClass) = Store : &:r0_3, r0_4
# 32| r0_9(glval<DerivedClass>) = VariableAddress[obj2] :
# 32| r0_10(DerivedClass) = NewObj :
# 32| r0_11(glval<DerivedClass>) = FunctionAddress[DerivedClass] :
# 32| r0_11(glval<null>) = FunctionAddress[DerivedClass] :
# 32| r0_12(Int32) = Constant[1] :
# 32| v0_13(Void) = Call : func:r0_11, this:r0_10, 0:r0_12
# 32| mu0_14(null) = ^CallSideEffect : ~mu0_2
# 32| mu0_15(DerivedClass) = Store : &:r0_9, r0_10
# 33| r0_16(glval<DerivedClass>) = VariableAddress[obj3] :
# 33| r0_17(DerivedClass) = NewObj :
# 33| r0_18(glval<DerivedClass>) = FunctionAddress[DerivedClass] :
# 33| r0_18(glval<null>) = FunctionAddress[DerivedClass] :
# 33| r0_19(Int32) = Constant[1] :
# 33| r0_20(Int32) = Constant[2] :
# 33| v0_21(Void) = Call : func:r0_18, this:r0_17, 0:r0_19, 1:r0_20
@@ -315,6 +315,124 @@ crement.cs:
# 3| v0_35(Void) = UnmodeledUse : mu*
# 3| v0_36(Void) = ExitFunction :
delegates.cs:
# 6| System.Int32 Delegates.returns(System.Int32)
# 6| Block 0
# 6| v0_0(Void) = EnterFunction :
# 6| mu0_1(null) = AliasedDefinition :
# 6| mu0_2(null) = UnmodeledDefinition :
# 6| r0_3(glval<Int32>) = VariableAddress[ret] :
# 6| mu0_4(Int32) = InitializeParameter[ret] : &:r0_3
# 8| r0_5(glval<Int32>) = VariableAddress[#return] :
# 8| r0_6(glval<Int32>) = VariableAddress[ret] :
# 8| r0_7(Int32) = Load : &:r0_6, ~mu0_2
# 8| mu0_8(Int32) = Store : &:r0_5, r0_7
# 6| r0_9(glval<Int32>) = VariableAddress[#return] :
# 6| v0_10(Void) = ReturnValue : &:r0_9, ~mu0_2
# 6| v0_11(Void) = UnmodeledUse : mu*
# 6| v0_12(Void) = ExitFunction :
# 11| System.Void Delegates.Main()
# 11| Block 0
# 11| v0_0(Void) = EnterFunction :
# 11| mu0_1(null) = AliasedDefinition :
# 11| mu0_2(null) = UnmodeledDefinition :
# 12| r0_3(glval<Del>) = VariableAddress[del1] :
# 12| r0_4(Del) = NewObj :
# 12| r0_5(glval<null>) = FunctionAddress[Del] :
# 12| r0_6(glval<Del>) = FunctionAddress[returns] :
# 12| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6
# 12| mu0_8(null) = ^CallSideEffect : ~mu0_2
# 12| mu0_9(Del) = Store : &:r0_3, r0_4
# 13| r0_10(glval<Del>) = VariableAddress[del1] :
# 13| r0_11(Del) = Load : &:r0_10, ~mu0_2
# 13| r0_12(glval<null>) = FunctionAddress[Invoke] :
# 13| r0_13(Int32) = Constant[5] :
# 13| v0_14(Void) = Call : func:r0_12, this:r0_11, 0:r0_13
# 13| mu0_15(null) = ^CallSideEffect : ~mu0_2
# 11| v0_16(Void) = ReturnVoid :
# 11| v0_17(Void) = UnmodeledUse : mu*
# 11| v0_18(Void) = ExitFunction :
foreach.cs:
# 4| System.Void ForEach.Main()
# 4| Block 0
# 4| v0_0(Void) = EnterFunction :
# 4| mu0_1(null) = AliasedDefinition :
# 4| mu0_2(null) = UnmodeledDefinition :
# 5| r0_3(glval<Int32[]>) = VariableAddress[a_array] :
# 5| mu0_4(Int32[]) = Uninitialized[a_array] : &:r0_3
# 5| r0_5(Int32) = Constant[0] :
# 5| r0_6(glval<Int32>) = PointerAdd : r0_3, r0_5
# 5| r0_7(Int32) = Constant[1] :
# 5| mu0_8(Int32) = Store : &:r0_6, r0_7
# 5| r0_9(Int32) = Constant[1] :
# 5| r0_10(glval<Int32>) = PointerAdd : r0_3, r0_9
# 5| r0_11(Int32) = Constant[2] :
# 5| mu0_12(Int32) = Store : &:r0_10, r0_11
# 5| r0_13(Int32) = Constant[2] :
# 5| r0_14(glval<Int32>) = PointerAdd : r0_3, r0_13
# 5| r0_15(Int32) = Constant[3] :
# 5| mu0_16(Int32) = Store : &:r0_14, r0_15
# 5| r0_17(Int32) = Constant[3] :
# 5| r0_18(glval<Int32>) = PointerAdd : r0_3, r0_17
# 5| r0_19(Int32) = Constant[4] :
# 5| mu0_20(Int32) = Store : &:r0_18, r0_19
# 5| r0_21(Int32) = Constant[4] :
# 5| r0_22(glval<Int32>) = PointerAdd : r0_3, r0_21
# 5| r0_23(Int32) = Constant[5] :
# 5| mu0_24(Int32) = Store : &:r0_22, r0_23
# 5| r0_25(Int32) = Constant[5] :
# 5| r0_26(glval<Int32>) = PointerAdd : r0_3, r0_25
# 5| r0_27(Int32) = Constant[6] :
# 5| mu0_28(Int32) = Store : &:r0_26, r0_27
# 5| r0_29(Int32) = Constant[6] :
# 5| r0_30(glval<Int32>) = PointerAdd : r0_3, r0_29
# 5| r0_31(Int32) = Constant[7] :
# 5| mu0_32(Int32) = Store : &:r0_30, r0_31
# 7| r0_33(glval<IEnumerator>) = VariableAddress[#temp7:9] :
# 7| r0_34(glval<Int32[]>) = VariableAddress[a_array] :
# 7| r0_35(Int32[]) = Load : &:r0_34, ~mu0_2
# 7| r0_36(glval<null>) = FunctionAddress[GetEnumerator] :
# 7| r0_37(IEnumerator) = Call : func:r0_36, this:r0_35
# 7| mu0_38(null) = ^CallSideEffect : ~mu0_2
# 7| mu0_39(IEnumerator) = Store : &:r0_33, r0_37
#-----| Goto -> Block 1
# 7| Block 1
# 7| r1_0(glval<Boolean>) = VariableAddress[#temp7:9] :
# 7| r1_1(Boolean) = Load : &:r1_0, ~mu0_2
# 7| r1_2(glval<null>) = FunctionAddress[MoveNext] :
# 7| r1_3(Boolean) = Call : func:r1_2, this:r1_1
# 7| mu1_4(null) = ^CallSideEffect : ~mu0_2
# 7| v1_5(Void) = ConditionalBranch : r1_3
#-----| False -> Block 3
#-----| True -> Block 2
# 7| Block 2
# 7| r2_0(glval<Int32>) = VariableAddress[items] :
# 7| r2_1(glval<Boolean>) = VariableAddress[#temp7:9] :
# 7| r2_2(Boolean) = Load : &:r2_1, ~mu0_2
# 7| r2_3(glval<null>) = FunctionAddress[get_Current] :
# 7| r2_4(Int32) = Call : func:r2_3, this:r2_2
# 7| mu2_5(null) = ^CallSideEffect : ~mu0_2
# 7| mu2_6(Int32) = Store : &:r2_0, r2_4
# 9| r2_7(glval<Int32>) = VariableAddress[x] :
# 9| r2_8(glval<Int32>) = VariableAddress[items] :
# 9| r2_9(Int32) = Load : &:r2_8, ~mu0_2
# 9| mu2_10(Int32) = Store : &:r2_7, r2_9
#-----| Goto (back edge) -> Block 1
# 7| Block 3
# 7| r3_0(glval<Boolean>) = VariableAddress[#temp7:9] :
# 7| r3_1(Boolean) = Load : &:r3_0, ~mu0_2
# 7| r3_2(glval<null>) = FunctionAddress[Dispose] :
# 7| v3_3(Void) = Call : func:r3_2, this:r3_1
# 7| mu3_4(null) = ^CallSideEffect : ~mu0_2
# 4| v3_5(Void) = ReturnVoid :
# 4| v3_6(Void) = UnmodeledUse : mu*
# 4| v3_7(Void) = ExitFunction :
func_with_param_call.cs:
# 5| System.Int32 test_call_with_param.f(System.Int32,System.Int32)
# 5| Block 0
@@ -343,7 +461,7 @@ func_with_param_call.cs:
# 10| mu0_1(null) = AliasedDefinition :
# 10| mu0_2(null) = UnmodeledDefinition :
# 12| r0_3(glval<Int32>) = VariableAddress[#return] :
# 12| r0_4(glval<Int32>) = FunctionAddress[f] :
# 12| r0_4(glval<null>) = FunctionAddress[f] :
# 12| r0_5(Int32) = Constant[2] :
# 12| r0_6(Int32) = Constant[3] :
# 12| r0_7(Int32) = Call : func:r0_4, 0:r0_5, 1:r0_6
@@ -385,46 +503,46 @@ inheritance_polymorphism.cs:
# 23| System.Void Program.Main()
# 23| Block 0
# 23| v0_0(Void) = EnterFunction :
# 23| mu0_1(null) = AliasedDefinition :
# 23| mu0_2(null) = UnmodeledDefinition :
# 25| r0_3(glval<B>) = VariableAddress[objB] :
# 25| r0_4(B) = NewObj :
# 25| r0_5(glval<B>) = FunctionAddress[B] :
# 25| v0_6(Void) = Call : func:r0_5, this:r0_4
# 25| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 25| mu0_8(B) = Store : &:r0_3, r0_4
# 26| r0_9(glval<B>) = VariableAddress[objB] :
# 26| r0_10(B) = Load : &:r0_9, ~mu0_2
# 26| r0_11(glval<Int32>) = FunctionAddress[function] :
# 26| r0_12(Int32) = Call : func:r0_11, this:r0_10
# 26| mu0_13(null) = ^CallSideEffect : ~mu0_2
# 29| r0_14(glval<A>) = VariableAddress[objA] :
# 29| mu0_15(A) = Uninitialized[objA] : &:r0_14
# 30| r0_16(glval<B>) = VariableAddress[objB] :
# 30| r0_17(A) = Convert : r0_16
# 30| r0_18(glval<A>) = VariableAddress[objA] :
# 30| mu0_19(A) = Store : &:r0_18, r0_17
# 31| r0_20(glval<A>) = VariableAddress[objA] :
# 31| r0_21(A) = Load : &:r0_20, ~mu0_2
# 31| r0_22(glval<Int32>) = FunctionAddress[function] :
# 31| r0_23(Int32) = Call : func:r0_22, this:r0_21
# 31| mu0_24(null) = ^CallSideEffect : ~mu0_2
# 33| r0_25(glval<A>) = VariableAddress[objC] :
# 33| r0_26(C) = NewObj :
# 33| r0_27(glval<C>) = FunctionAddress[C] :
# 33| v0_28(Void) = Call : func:r0_27, this:r0_26
# 33| mu0_29(null) = ^CallSideEffect : ~mu0_2
# 33| r0_30(A) = Convert : r0_26
# 33| mu0_31(C) = Store : &:r0_25, r0_30
# 34| r0_32(glval<A>) = VariableAddress[objC] :
# 34| r0_33(A) = Load : &:r0_32, ~mu0_2
# 34| r0_34(glval<Int32>) = FunctionAddress[function] :
# 34| r0_35(Int32) = Call : func:r0_34, this:r0_33
# 34| mu0_36(null) = ^CallSideEffect : ~mu0_2
# 23| v0_37(Void) = ReturnVoid :
# 23| v0_38(Void) = UnmodeledUse : mu*
# 23| v0_39(Void) = ExitFunction :
# 23| v0_0(Void) = EnterFunction :
# 23| mu0_1(null) = AliasedDefinition :
# 23| mu0_2(null) = UnmodeledDefinition :
# 25| r0_3(glval<B>) = VariableAddress[objB] :
# 25| r0_4(B) = NewObj :
# 25| r0_5(glval<null>) = FunctionAddress[B] :
# 25| v0_6(Void) = Call : func:r0_5, this:r0_4
# 25| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 25| mu0_8(B) = Store : &:r0_3, r0_4
# 26| r0_9(glval<B>) = VariableAddress[objB] :
# 26| r0_10(B) = Load : &:r0_9, ~mu0_2
# 26| r0_11(glval<null>) = FunctionAddress[function] :
# 26| r0_12(Int32) = Call : func:r0_11, this:r0_10
# 26| mu0_13(null) = ^CallSideEffect : ~mu0_2
# 29| r0_14(glval<A>) = VariableAddress[objA] :
# 29| mu0_15(A) = Uninitialized[objA] : &:r0_14
# 30| r0_16(glval<B>) = VariableAddress[objB] :
# 30| r0_17(A) = Convert : r0_16
# 30| r0_18(glval<A>) = VariableAddress[objA] :
# 30| mu0_19(A) = Store : &:r0_18, r0_17
# 31| r0_20(glval<A>) = VariableAddress[objA] :
# 31| r0_21(A) = Load : &:r0_20, ~mu0_2
# 31| r0_22(glval<null>) = FunctionAddress[function] :
# 31| r0_23(Int32) = Call : func:r0_22, this:r0_21
# 31| mu0_24(null) = ^CallSideEffect : ~mu0_2
# 33| r0_25(glval<A>) = VariableAddress[objC] :
# 33| r0_26(C) = NewObj :
# 33| r0_27(glval<null>) = FunctionAddress[C] :
# 33| v0_28(Void) = Call : func:r0_27, this:r0_26
# 33| mu0_29(null) = ^CallSideEffect : ~mu0_2
# 33| r0_30(A) = Convert : r0_26
# 33| mu0_31(C) = Store : &:r0_25, r0_30
# 34| r0_32(glval<A>) = VariableAddress[objC] :
# 34| r0_33(A) = Load : &:r0_32, ~mu0_2
# 34| r0_34(glval<null>) = FunctionAddress[function] :
# 34| r0_35(Int32) = Call : func:r0_34, this:r0_33
# 34| mu0_36(null) = ^CallSideEffect : ~mu0_2
# 23| v0_37(Void) = ReturnVoid :
# 23| v0_38(Void) = UnmodeledUse : mu*
# 23| v0_39(Void) = ExitFunction :
isexpr.cs:
# 8| System.Void IsExpr.Main()
@@ -485,6 +603,58 @@ isexpr.cs:
# 18| v6_0(Void) = NoOp :
#-----| Goto -> Block 1
lock.cs:
# 5| System.Void LockTest.A()
# 5| Block 0
# 5| v0_0(Void) = EnterFunction :
# 5| mu0_1(null) = AliasedDefinition :
# 5| mu0_2(null) = UnmodeledDefinition :
# 7| r0_3(glval<Object>) = VariableAddress[object] :
# 7| r0_4(Object) = NewObj :
# 7| r0_5(glval<null>) = FunctionAddress[Object] :
# 7| v0_6(Void) = Call : func:r0_5, this:r0_4
# 7| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 7| mu0_8(Object) = Store : &:r0_3, r0_4
# 8| r0_9(glval<Object>) = VariableAddress[#temp8:9] :
# 8| r0_10(glval<Object>) = VariableAddress[object] :
# 8| r0_11(Object) = Load : &:r0_10, ~mu0_2
# 8| mu0_12(Object) = Store : &:r0_9, r0_11
# 8| r0_13(glval<Boolean>) = VariableAddress[#temp8:9] :
# 8| r0_14(Boolean) = Constant[false] :
# 8| mu0_15(Boolean) = Store : &:r0_13, r0_14
# 8| r0_16(glval<null>) = FunctionAddress[Enter] :
# 8| r0_17(glval<Object>) = VariableAddress[#temp8:9] :
# 8| r0_18(Object) = Load : &:r0_17, ~mu0_2
# 8| r0_19(glval<Boolean>) = VariableAddress[#temp8:9] :
# 8| v0_20(Void) = Call : func:r0_16, 0:r0_18, 1:r0_19
# 8| mu0_21(null) = ^CallSideEffect : ~mu0_2
# 10| r0_22(glval<null>) = FunctionAddress[WriteLine] :
# 10| r0_23(glval<Object>) = VariableAddress[object] :
# 10| r0_24(Object) = Load : &:r0_23, ~mu0_2
# 10| r0_25(glval<null>) = FunctionAddress[ToString] :
# 10| r0_26(String) = Call : func:r0_25, this:r0_24
# 10| mu0_27(null) = ^CallSideEffect : ~mu0_2
# 10| v0_28(Void) = Call : func:r0_22, 0:r0_26
# 10| mu0_29(null) = ^CallSideEffect : ~mu0_2
# 8| r0_30(glval<Boolean>) = VariableAddress[#temp8:9] :
# 8| r0_31(Boolean) = Load : &:r0_30, ~mu0_2
# 8| v0_32(Void) = ConditionalBranch : r0_31
#-----| False -> Block 1
#-----| True -> Block 2
# 5| Block 1
# 5| v1_0(Void) = ReturnVoid :
# 5| v1_1(Void) = UnmodeledUse : mu*
# 5| v1_2(Void) = ExitFunction :
# 8| Block 2
# 8| r2_0(glval<null>) = FunctionAddress[Exit] :
# 8| r2_1(glval<Object>) = VariableAddress[#temp8:9] :
# 8| r2_2(Object) = Load : &:r2_1, ~mu0_2
# 8| v2_3(Void) = Call : func:r2_0, 0:r2_2
# 8| mu2_4(null) = ^CallSideEffect : ~mu0_2
#-----| Goto -> Block 1
obj_creation.cs:
# 7| System.Void ObjCreation.MyClass..ctor()
# 7| Block 0
@@ -521,14 +691,14 @@ obj_creation.cs:
# 17| mu0_2(null) = UnmodeledDefinition :
# 19| r0_3(glval<MyClass>) = VariableAddress[obj] :
# 19| r0_4(MyClass) = NewObj :
# 19| r0_5(glval<MyClass>) = FunctionAddress[MyClass] :
# 19| r0_5(glval<null>) = FunctionAddress[MyClass] :
# 19| r0_6(Int32) = Constant[100] :
# 19| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6
# 19| mu0_8(null) = ^CallSideEffect : ~mu0_2
# 19| mu0_9(MyClass) = Store : &:r0_3, r0_4
# 20| r0_10(glval<MyClass>) = VariableAddress[obj_initlist] :
# 20| r0_11(MyClass) = NewObj :
# 20| r0_12(glval<MyClass>) = FunctionAddress[MyClass] :
# 20| r0_12(glval<null>) = FunctionAddress[MyClass] :
# 20| v0_13(Void) = Call : func:r0_12, this:r0_11
# 20| mu0_14(null) = ^CallSideEffect : ~mu0_2
# 20| r0_15(Int32) = Constant[101] :
@@ -554,7 +724,7 @@ prop.cs:
# 7| r0_3(glval<PropClass>) = InitializeThis :
# 9| r0_4(glval<Int32>) = VariableAddress[#return] :
# 9| r0_5(PropClass) = CopyValue : r0_3
# 9| r0_6(glval<Int32>) = FunctionAddress[func] :
# 9| r0_6(glval<null>) = FunctionAddress[func] :
# 9| r0_7(Int32) = Call : func:r0_6, this:r0_5
# 9| mu0_8(null) = ^CallSideEffect : ~mu0_2
# 9| mu0_9(Int32) = Store : &:r0_4, r0_7
@@ -601,20 +771,20 @@ prop.cs:
# 26| mu0_2(null) = UnmodeledDefinition :
# 28| r0_3(glval<PropClass>) = VariableAddress[obj] :
# 28| r0_4(PropClass) = NewObj :
# 28| r0_5(glval<PropClass>) = FunctionAddress[PropClass] :
# 28| r0_5(glval<null>) = FunctionAddress[PropClass] :
# 28| v0_6(Void) = Call : func:r0_5, this:r0_4
# 28| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 28| mu0_8(PropClass) = Store : &:r0_3, r0_4
# 29| r0_9(glval<PropClass>) = VariableAddress[obj] :
# 29| r0_10(PropClass) = Load : &:r0_9, ~mu0_2
# 29| r0_11(glval<Int32>) = FunctionAddress[set_Prop] :
# 29| r0_11(glval<null>) = FunctionAddress[set_Prop] :
# 29| r0_12(Int32) = Constant[5] :
# 29| r0_13(Int32) = Call : func:r0_11, this:r0_10, 0:r0_12
# 29| v0_13(Void) = Call : func:r0_11, this:r0_10, 0:r0_12
# 29| mu0_14(null) = ^CallSideEffect : ~mu0_2
# 30| r0_15(glval<Int32>) = VariableAddress[x] :
# 30| r0_16(glval<PropClass>) = VariableAddress[obj] :
# 30| r0_17(PropClass) = Load : &:r0_16, ~mu0_2
# 30| r0_18(glval<Int32>) = FunctionAddress[get_Prop] :
# 30| r0_18(glval<null>) = FunctionAddress[get_Prop] :
# 30| r0_19(Int32) = Call : func:r0_18, this:r0_17
# 30| mu0_20(null) = ^CallSideEffect : ~mu0_2
# 30| r0_21(Int32) = Load : &:r0_19, ~mu0_2
@@ -644,7 +814,7 @@ simple_call.cs:
# 10| mu0_2(null) = UnmodeledDefinition :
# 10| r0_3(glval<test_simple_call>) = InitializeThis :
# 12| r0_4(glval<Int32>) = VariableAddress[#return] :
# 12| r0_5(glval<Int32>) = FunctionAddress[f] :
# 12| r0_5(glval<null>) = FunctionAddress[f] :
# 12| r0_6(Int32) = Call : func:r0_5
# 12| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 12| mu0_8(Int32) = Store : &:r0_4, r0_6
@@ -743,7 +913,7 @@ stmts.cs:
# 22| mu0_2(null) = UnmodeledDefinition :
# 24| r0_3(glval<Object>) = VariableAddress[caseSwitch] :
# 24| r0_4(Object) = NewObj :
# 24| r0_5(glval<Object>) = FunctionAddress[Object] :
# 24| r0_5(glval<null>) = FunctionAddress[Object] :
# 24| v0_6(Void) = Call : func:r0_5, this:r0_4
# 24| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 24| mu0_8(Object) = Store : &:r0_3, r0_4
@@ -829,7 +999,7 @@ stmts.cs:
# 52| Block 3
# 52| r3_0(glval<Exception>) = VariableAddress[#throw52:17] :
# 52| r3_1(Exception) = NewObj :
# 52| r3_2(glval<Exception>) = FunctionAddress[Exception] :
# 52| r3_2(glval<null>) = FunctionAddress[Exception] :
# 52| v3_3(Void) = Call : func:r3_2, this:r3_1
# 52| mu3_4(null) = ^CallSideEffect : ~mu0_2
# 52| mu3_5(Exception) = Store : &:r3_0, r3_1