зеркало из https://github.com/github/codeql.git
Initial restructure
The `raw/internal` folder has been restructured to better enhance code sharing between compiler generated elements and AST generated elements. The translated calls classes have been refactored to better fit the C# library. A new folder has been added, `common` that provides blueprints for the classes that deal with translations of calls, declarations, exprs and conditions. Several `TranslatedX.qll` files have been modified so that they use those blueprint classes.
This commit is contained in:
Родитель
aa009d07fd
Коммит
80b7512fe2
|
@ -54,6 +54,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 +193,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,67 @@ 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.TranslatedCallBlueprint
|
||||
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
|
||||
* (eg. `MethodCall`) or a constructor call (eg. `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)
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() {
|
||||
if exists(this.getQualifier())
|
||||
then result = this.getQualifier().getFirstInstruction()
|
||||
else result = this.getFirstCallTargetInstruction()
|
||||
abstract class TranslatedCall extends TranslatedExpr, TranslatedCallBlueprint {
|
||||
final override Instruction getResult() {
|
||||
result = TranslatedCallBlueprint.super.getResult()
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
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 predicate hasArguments() {
|
||||
exists(expr.getArgument(0))
|
||||
}
|
||||
|
||||
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 +76,45 @@ 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 {
|
||||
TranslatedConstructorCall() {
|
||||
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 predicate hasArguments() {
|
||||
exists(expr.getArgument(0))
|
||||
}
|
||||
|
||||
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,26 +4,23 @@ private import semmle.code.csharp.ir.implementation.internal.OperandTag
|
|||
private import InstructionTag
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import common.TranslatedConditionBlueprint
|
||||
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
|
||||
}
|
||||
|
||||
TranslatedCondition getTranslatedCondition(Expr expr) { result.getExpr() = expr }
|
||||
|
||||
abstract class TranslatedCondition extends TranslatedElement {
|
||||
abstract class TranslatedCondition extends ConditionBlueprint {
|
||||
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 Expr getExpr() {
|
||||
result = expr
|
||||
}
|
||||
|
||||
final override Callable getFunction() { result = expr.getEnclosingCallable() }
|
||||
|
||||
|
@ -56,12 +53,12 @@ abstract class TranslatedFlexibleCondition extends TranslatedCondition, Conditio
|
|||
class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
|
||||
override ParenthesizedExpr expr;
|
||||
|
||||
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
final override Instruction getChildTrueSuccessor(ConditionBlueprint child) {
|
||||
child = this.getOperand() and
|
||||
result = this.getConditionContext().getChildTrueSuccessor(this)
|
||||
}
|
||||
|
||||
final override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
final override Instruction getChildFalseSuccessor(ConditionBlueprint child) {
|
||||
child = this.getOperand() and
|
||||
result = this.getConditionContext().getChildFalseSuccessor(this)
|
||||
}
|
||||
|
@ -74,12 +71,12 @@ class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
|
|||
class TranslatedNotCondition extends TranslatedFlexibleCondition {
|
||||
override LogicalNotExpr expr;
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
override Instruction getChildTrueSuccessor(ConditionBlueprint child) {
|
||||
child = this.getOperand() and
|
||||
result = this.getConditionContext().getChildFalseSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
override Instruction getChildFalseSuccessor(ConditionBlueprint child) {
|
||||
child = this.getOperand() and
|
||||
result = this.getConditionContext().getChildTrueSuccessor(this)
|
||||
}
|
||||
|
@ -131,15 +128,18 @@ abstract class TranslatedBinaryLogicalOperation extends TranslatedNativeConditio
|
|||
class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
|
||||
TranslatedLogicalAndExpr() { expr instanceof LogicalAndExpr }
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
child = this.getLeftOperand() and
|
||||
result = this.getRightOperand().getFirstInstruction()
|
||||
or
|
||||
child = this.getRightOperand() and
|
||||
result = this.getConditionContext().getChildTrueSuccessor(this)
|
||||
override Instruction getChildTrueSuccessor(ConditionBlueprint child) {
|
||||
(
|
||||
child = this.getLeftOperand() and
|
||||
result = this.getRightOperand().getFirstInstruction()
|
||||
) or
|
||||
(
|
||||
child = this.getRightOperand() and
|
||||
result = this.getConditionContext().getChildTrueSuccessor(this)
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
override Instruction getChildFalseSuccessor(ConditionBlueprint child) {
|
||||
child = this.getAnOperand() and
|
||||
result = this.getConditionContext().getChildFalseSuccessor(this)
|
||||
}
|
||||
|
@ -148,57 +148,34 @@ class TranslatedLogicalAndExpr extends TranslatedBinaryLogicalOperation {
|
|||
class TranslatedLogicalOrExpr extends TranslatedBinaryLogicalOperation {
|
||||
override LogicalOrExpr expr;
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
override Instruction getChildTrueSuccessor(ConditionBlueprint child) {
|
||||
child = getAnOperand() and
|
||||
result = this.getConditionContext().getChildTrueSuccessor(this)
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
child = this.getLeftOperand() and
|
||||
result = getRightOperand().getFirstInstruction()
|
||||
or
|
||||
child = this.getRightOperand() and
|
||||
result = this.getConditionContext().getChildFalseSuccessor(this)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedValueCondition extends TranslatedCondition, TTranslatedValueCondition {
|
||||
TranslatedValueCondition() { this = TTranslatedValueCondition(expr) }
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = getValueExpr() }
|
||||
|
||||
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
|
||||
override Instruction getChildFalseSuccessor(ConditionBlueprint child) {
|
||||
(
|
||||
kind instanceof TrueEdge and
|
||||
result = this.getConditionContext().getChildTrueSuccessor(this)
|
||||
or
|
||||
kind instanceof FalseEdge and
|
||||
child = this.getLeftOperand() and
|
||||
result = getRightOperand().getFirstInstruction()
|
||||
) or
|
||||
(
|
||||
child = this.getRightOperand() and
|
||||
result = this.getConditionContext().getChildFalseSuccessor(this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = ValueConditionConditionalBranchTag() and
|
||||
operandTag instanceof ConditionOperandTag and
|
||||
class TranslatedValueCondition extends TranslatedCondition, ValueConditionBlueprint,
|
||||
TTranslatedValueCondition {
|
||||
TranslatedValueCondition() {
|
||||
this = TTranslatedValueCondition(expr)
|
||||
}
|
||||
|
||||
override TranslatedExpr getValueExpr() {
|
||||
result = getTranslatedExpr(expr)
|
||||
}
|
||||
|
||||
override Instruction valueExprResult() {
|
||||
result = this.getValueExpr().getResult()
|
||||
}
|
||||
|
||||
private TranslatedExpr getValueExpr() { result = getTranslatedExpr(expr) }
|
||||
}
|
||||
|
|
|
@ -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.TranslatedDeclarationBlueprint
|
||||
|
||||
/**
|
||||
* Gets the `TranslatedDeclaration` that represents the declaration
|
||||
|
@ -35,58 +36,28 @@ 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, LocalVariableDeclarationBlueprint,
|
||||
InitializationContext {
|
||||
LocalVariable var;
|
||||
|
||||
TranslatedLocalVariableDeclaration() { var = expr.getVariable() }
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() }
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
|
||||
TranslatedLocalVariableDeclaration() {
|
||||
var = expr.getVariable()
|
||||
}
|
||||
|
||||
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 +66,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 +81,7 @@ 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()
|
||||
override predicate isInitializedByElement() {
|
||||
expr.getParent() instanceof IsExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 }
|
||||
}
|
||||
|
|
|
@ -22,6 +22,12 @@ ArrayType getArrayOfDim(int dim, Type type) {
|
|||
result.getElementType() = type
|
||||
}
|
||||
|
||||
predicate canCreateCompilerGeneratedElement (int nth) {
|
||||
// For now we allow a max of 15 compiler generated elements
|
||||
nth in [0 .. 14]
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the "real" parent of `expr`. This predicate treats conversions as if
|
||||
* they were explicit nodes in the expression tree, rather than as implicit
|
||||
|
@ -253,8 +259,13 @@ newtype TTranslatedElement =
|
|||
)
|
||||
} or
|
||||
// A local declaration
|
||||
TTranslatedDeclaration(LocalVariableDeclExpr entry)
|
||||
|
||||
TTranslatedDeclaration(LocalVariableDeclExpr entry) or
|
||||
// A compiler generated element, generated by `generatedBy` during the
|
||||
// desugaring process
|
||||
TTranslatedCompilerGeneratedElement(Element generatedBy, int index) {
|
||||
canCreateCompilerGeneratedElement(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the first explicitly initialized element in `initList`
|
||||
* whose index is greater than `afterElementIndex`, where `afterElementIndex`
|
||||
|
|
|
@ -9,8 +9,9 @@ private import TranslatedDeclaration
|
|||
private import TranslatedElement
|
||||
private import TranslatedFunction
|
||||
private import TranslatedInitialization
|
||||
private import TranslatedFunction
|
||||
private import TranslatedStmt
|
||||
private import common.TranslatedConditionBlueprint
|
||||
private import common.TranslatedCallBlueprint
|
||||
private import common.TranslatedExprBlueprint
|
||||
import TranslatedCall
|
||||
private import semmle.code.csharp.ir.Util
|
||||
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
|
@ -35,14 +36,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 TranslatedExprBlueprint {
|
||||
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 +239,12 @@ class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
|||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) { none() }
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
override Instruction getChildTrueSuccessor(ConditionBlueprint child) {
|
||||
child = this.getCondition() and
|
||||
result = this.getInstruction(ConditionValueTrueTempAddressTag())
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
override Instruction getChildFalseSuccessor(ConditionBlueprint child) {
|
||||
child = this.getCondition() and
|
||||
result = this.getInstruction(ConditionValueFalseTempAddressTag())
|
||||
}
|
||||
|
@ -746,8 +742,7 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
|
|||
// and not the LHS (the address of the LHS is generated during
|
||||
// the translation of the initialization).
|
||||
(
|
||||
expr.getParent() instanceof LocalVariableDeclAndInitExpr
|
||||
implies
|
||||
expr.getParent() instanceof LocalVariableDeclAndInitExpr implies
|
||||
expr = expr.getParent().(LocalVariableDeclAndInitExpr).getInitializer()
|
||||
)
|
||||
}
|
||||
|
@ -1452,13 +1447,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 +1604,12 @@ class TranslatedConditionalExpr extends TranslatedNonConstantExpr, ConditionCont
|
|||
)
|
||||
}
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
override Instruction getChildTrueSuccessor(ConditionBlueprint child) {
|
||||
child = this.getCondition() and
|
||||
result = this.getThen().getFirstInstruction()
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
override Instruction getChildFalseSuccessor(ConditionBlueprint child) {
|
||||
child = this.getCondition() and
|
||||
result = this.getElse().getFirstInstruction()
|
||||
}
|
||||
|
|
|
@ -175,7 +175,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) {
|
||||
|
@ -389,8 +389,7 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ
|
|||
}
|
||||
|
||||
// TODO: Possibly refactor into something simpler
|
||||
abstract class TranslatedConstructorCallFromConstructor extends TranslatedElement,
|
||||
StructorCallContext {
|
||||
abstract class TranslatedConstructorCallFromConstructor extends TranslatedElement, ConstructorCallContext {
|
||||
Call call;
|
||||
|
||||
final override Language::AST getAST() { result = call }
|
||||
|
|
|
@ -8,6 +8,7 @@ private import TranslatedElement
|
|||
private import TranslatedExpr
|
||||
private import TranslatedFunction
|
||||
private import TranslatedInitialization
|
||||
private import common.TranslatedConditionBlueprint
|
||||
private import IRInternal
|
||||
private import semmle.code.csharp.ir.internal.IRUtilities
|
||||
|
||||
|
@ -243,10 +244,14 @@ class TranslatedTryStmt extends TranslatedStmt {
|
|||
none()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() }
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
result = this.getBody().getFirstInstruction()
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = this.getCatchClause(_) and result = this.getFinally().getFirstInstruction()
|
||||
or
|
||||
|
@ -562,12 +567,12 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
|
|||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
override Instruction getChildTrueSuccessor(ConditionBlueprint child) {
|
||||
child = this.getCondition() and
|
||||
result = this.getThen().getFirstInstruction()
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
override Instruction getChildFalseSuccessor(ConditionBlueprint child) {
|
||||
child = this.getCondition() and
|
||||
if this.hasElse()
|
||||
then result = this.getElse().getFirstInstruction()
|
||||
|
@ -615,11 +620,11 @@ abstract class TranslatedLoop extends TranslatedStmt, ConditionContext {
|
|||
|
||||
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
final override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
||||
override final Instruction getChildTrueSuccessor(ConditionBlueprint child) {
|
||||
child = this.getCondition() and result = this.getBody().getFirstInstruction()
|
||||
}
|
||||
|
||||
final override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
||||
override final Instruction getChildFalseSuccessor(ConditionBlueprint child) {
|
||||
child = this.getCondition() and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
/**
|
||||
* Contains an abstract class that serves as a blueprint 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 TranslatedExprBlueprint
|
||||
|
||||
abstract class TranslatedCallBlueprint 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 TranslatedExprBlueprint 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 `TranslatedExprBlueprint` 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 TranslatedExprBlueprint 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.
|
||||
*/
|
||||
abstract predicate hasArguments();
|
||||
|
||||
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 blueprints.
|
||||
*/
|
||||
|
||||
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(ConditionBlueprint child);
|
||||
|
||||
abstract Instruction getChildFalseSuccessor(ConditionBlueprint child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract class that serves as a blueprint for the classes that deal with both the AST generated conditions
|
||||
* and the compiler generated ones (captures the common patterns).
|
||||
*/
|
||||
abstract class ConditionBlueprint extends TranslatedElement {
|
||||
final ConditionContext getConditionContext() {
|
||||
result = getParent()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract class that serves as a blueprint for the classes that deal with both the AST generated _value_ conditions
|
||||
* and the compiler generated ones (captures the common patterns).
|
||||
*/
|
||||
abstract class ValueConditionBlueprint extends ConditionBlueprint {
|
||||
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 blueprint 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 LocalVariableDeclarationBlueprint 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();
|
||||
|
||||
/**
|
||||
* Predicate that 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 blueprint 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 TranslatedExprBlueprint extends TranslatedElement {
|
||||
/**
|
||||
* Gets the instruction that produces the result of the expression.
|
||||
*/
|
||||
abstract Instruction getResult();
|
||||
}
|
|
@ -0,0 +1,368 @@
|
|||
import csharp
|
||||
|
||||
private int getMaxCallArgIndex() {
|
||||
result = max(int argIndex |
|
||||
exists(Call 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
|
||||
exists(Callable callable |
|
||||
callable.getNumberOfParameters() = argIndex
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TOperandTag =
|
||||
TAddressOperand() or
|
||||
TBufferSizeOperand() or
|
||||
TSideEffectOperand() or
|
||||
TLoadOperand() or
|
||||
TStoreValueOperand() or
|
||||
TUnaryOperand() or
|
||||
TLeftOperand() or
|
||||
TRightOperand() or
|
||||
TConditionOperand() or
|
||||
TUnmodeledUseOperand() or
|
||||
TCallTargetOperand() or
|
||||
TThisArgumentOperand() or
|
||||
TPositionalArgumentOperand(int argIndex) {
|
||||
argIndex in [0..getMaxCallArgIndex()]
|
||||
} or
|
||||
TChiTotalOperand() or
|
||||
TChiPartialOperand()
|
||||
|
||||
/**
|
||||
* Identifies the kind of operand on an instruction. Each `Instruction` has at
|
||||
* most one operand of any single `OperandTag`. The set of `OperandTag`s used by
|
||||
* an `Instruction` is determined by the instruction's opcode.
|
||||
*/
|
||||
abstract class OperandTag extends TOperandTag {
|
||||
abstract string toString();
|
||||
|
||||
abstract int getSortOrder();
|
||||
|
||||
string getLabel() {
|
||||
result = ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction).
|
||||
*/
|
||||
abstract class MemoryOperandTag extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand that consumes a register (non-memory) result.
|
||||
*/
|
||||
abstract class RegisterOperandTag extends OperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* A memory operand whose type may be different from the result type of its definition instruction.
|
||||
*/
|
||||
abstract class TypedOperandTag extends MemoryOperandTag {
|
||||
}
|
||||
|
||||
// Note: individual subtypes are listed in the order that the operands should
|
||||
// appear in the operand list of the instruction when printing.
|
||||
|
||||
/**
|
||||
* The address operand of an instruction that loads or stores a value from
|
||||
* memory (e.g. `Load`, `Store`, `InitializeParameter`, `IndirectReadSideEffect`).
|
||||
*/
|
||||
class AddressOperandTag extends RegisterOperandTag, TAddressOperand {
|
||||
override final string toString() {
|
||||
result = "Address"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 0
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "&:"
|
||||
}
|
||||
}
|
||||
|
||||
AddressOperandTag addressOperand() {
|
||||
result = TAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The buffer size operand of an instruction that represents a read or write of
|
||||
* a buffer.
|
||||
*/
|
||||
class BufferSizeOperand extends RegisterOperandTag, TBufferSizeOperand {
|
||||
override final string toString() {
|
||||
result = "BufferSize"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the read side effect of a `SideEffectInstruction`.
|
||||
*/
|
||||
class SideEffectOperandTag extends TypedOperandTag, TSideEffectOperand {
|
||||
override final string toString() {
|
||||
result = "SideEffect"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
SideEffectOperandTag sideEffectOperand() {
|
||||
result = TSideEffectOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of an instruction that loads a value from memory (e.g. `Load`,
|
||||
* `ReturnValue`, `ThrowValue`).
|
||||
*/
|
||||
class LoadOperandTag extends TypedOperandTag, TLoadOperand {
|
||||
override final string toString() {
|
||||
result = "Load"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 3
|
||||
}
|
||||
}
|
||||
|
||||
LoadOperandTag loadOperand() {
|
||||
result = TLoadOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The source value operand of a `Store` instruction.
|
||||
*/
|
||||
class StoreValueOperandTag extends RegisterOperandTag, TStoreValueOperand {
|
||||
override final string toString() {
|
||||
result = "StoreValue"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 4
|
||||
}
|
||||
}
|
||||
|
||||
StoreValueOperandTag storeValueOperand() {
|
||||
result = TStoreValueOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`, `Copy`).
|
||||
*/
|
||||
class UnaryOperandTag extends RegisterOperandTag, TUnaryOperand {
|
||||
override final string toString() {
|
||||
result = "Unary"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 5
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOperandTag unaryOperand() {
|
||||
result = TUnaryOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class LeftOperandTag extends RegisterOperandTag, TLeftOperand {
|
||||
override final string toString() {
|
||||
result = "Left"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 6
|
||||
}
|
||||
}
|
||||
|
||||
LeftOperandTag leftOperand() {
|
||||
result = TLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
|
||||
*/
|
||||
class RightOperandTag extends RegisterOperandTag, TRightOperand {
|
||||
override final string toString() {
|
||||
result = "Right"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 7
|
||||
}
|
||||
}
|
||||
|
||||
RightOperandTag rightOperand() {
|
||||
result = TRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
|
||||
*/
|
||||
class ConditionOperandTag extends RegisterOperandTag, TConditionOperand {
|
||||
override final string toString() {
|
||||
result = "Condition"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 8
|
||||
}
|
||||
}
|
||||
|
||||
ConditionOperandTag conditionOperand() {
|
||||
result = TConditionOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand of the special `UnmodeledUse` instruction, representing a value
|
||||
* whose set of uses is unknown.
|
||||
*/
|
||||
class UnmodeledUseOperandTag extends MemoryOperandTag, TUnmodeledUseOperand {
|
||||
override final string toString() {
|
||||
result = "UnmodeledUse"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 9
|
||||
}
|
||||
}
|
||||
|
||||
UnmodeledUseOperandTag unmodeledUseOperand() {
|
||||
result = TUnmodeledUseOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* The operand representing the target function of an `Call` instruction.
|
||||
*/
|
||||
class CallTargetOperandTag extends RegisterOperandTag, TCallTargetOperand {
|
||||
override final string toString() {
|
||||
result = "CallTarget"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 10
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "func:"
|
||||
}
|
||||
}
|
||||
|
||||
CallTargetOperandTag callTargetOperand() {
|
||||
result = TCallTargetOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call. This includes both
|
||||
* positional arguments (represented by `PositionalArgumentOperand`) and the
|
||||
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
|
||||
*/
|
||||
abstract class ArgumentOperandTag extends RegisterOperandTag {
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing the implicit 'this' argument to a member function
|
||||
* call.
|
||||
*/
|
||||
class ThisArgumentOperandTag extends ArgumentOperandTag, TThisArgumentOperand {
|
||||
ThisArgumentOperandTag() {
|
||||
this = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(this)"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 11
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "this:"
|
||||
}
|
||||
}
|
||||
|
||||
ThisArgumentOperandTag thisArgumentOperand() {
|
||||
result = TThisArgumentOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* An operand representing an argument to a function call.
|
||||
*/
|
||||
class PositionalArgumentOperandTag extends ArgumentOperandTag,
|
||||
TPositionalArgumentOperand {
|
||||
int argIndex;
|
||||
|
||||
PositionalArgumentOperandTag() {
|
||||
this = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
override final string toString() {
|
||||
result = "Arg(" + argIndex + ")"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 12 + argIndex
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = argIndex.toString() + ":"
|
||||
}
|
||||
|
||||
final int getArgIndex() {
|
||||
result = argIndex
|
||||
}
|
||||
}
|
||||
|
||||
PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
|
||||
result = TPositionalArgumentOperand(argIndex)
|
||||
}
|
||||
|
||||
class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand {
|
||||
override final string toString() {
|
||||
result = "ChiTotal"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 13
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "total:"
|
||||
}
|
||||
}
|
||||
|
||||
ChiTotalOperandTag chiTotalOperand() {
|
||||
result = TChiTotalOperand()
|
||||
}
|
||||
|
||||
class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand {
|
||||
override final string toString() {
|
||||
result = "ChiPartial"
|
||||
}
|
||||
|
||||
override final int getSortOrder() {
|
||||
result = 14
|
||||
}
|
||||
|
||||
override final string getLabel() {
|
||||
result = "partial:"
|
||||
}
|
||||
}
|
||||
|
||||
ChiPartialOperandTag chiPartialOperand() {
|
||||
result = TChiPartialOperand()
|
||||
}
|
|
@ -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
|
||||
|
@ -343,7 +343,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 +385,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()
|
||||
|
@ -521,14 +521,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 +554,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 +601,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 +644,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 +743,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 +829,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
|
||||
|
|
Загрузка…
Ссылка в новой задаче