mirror of
https://github.com/github/codeql.git
synced 2026-04-27 09:45:15 +02:00
Merge pull request #1845 from AndreiDiaconu1/ircsharp-compiler-generated
C# IR: Framework for translating compiler generated elements
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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()) }
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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() + ")"
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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() + ")"
|
||||
}
|
||||
}
|
||||
@@ -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() }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
15
csharp/ql/test/library-tests/ir/ir/delegates.cs
Normal file
15
csharp/ql/test/library-tests/ir/ir/delegates.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
12
csharp/ql/test/library-tests/ir/ir/foreach.cs
Normal file
12
csharp/ql/test/library-tests/ir/ir/foreach.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
csharp/ql/test/library-tests/ir/ir/lock.cs
Normal file
13
csharp/ql/test/library-tests/ir/ir/lock.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
class LockTest
|
||||
{
|
||||
static void A()
|
||||
{
|
||||
object @object = new object();
|
||||
lock (@object)
|
||||
{
|
||||
Console.WriteLine(@object.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user