mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Framework for the translation of compiler elements
Added a framework for the translation of compiler generated elements, so that the process of adding a new desugaring process is almost mechanical. The files in `internal` serve as the superclasses for all the compiler generated elements. The file `Common.qll` captures common patterns for the compiler generated code to improve code sharing (by pattern I mean an element that appears in multiple desugarings). For example the `try...finally` pattern appears in the desugaring process of both the `lock` and the `foreach` stmts, so a class the provides a blueprint for this pattern is exposed. Several other patterns are present. The expected output has also been updated (after a rebase) and it should be ignored.
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
/**
|
||||
* 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.TranslatedConditionBlueprint
|
||||
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBlueprint
|
||||
|
||||
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(ConditionBlueprint child) {
|
||||
child = getCondition() and
|
||||
result = getThen().getFirstInstruction()
|
||||
}
|
||||
|
||||
override Instruction getChildFalseSuccessor(ConditionBlueprint 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,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.TranslatedCallBlueprint
|
||||
private import TranslatedCompilerGeneratedElement
|
||||
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
|
||||
abstract class TranslatedCompilerGeneratedCall extends TranslatedCallBlueprint,
|
||||
TranslatedCompilerGeneratedElement {
|
||||
override final 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.TranslatedConditionBlueprint
|
||||
private import TranslatedCompilerGeneratedElement
|
||||
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
|
||||
abstract class TranslatedCompilerGeneratedValueCondition extends TranslatedCompilerGeneratedElement,
|
||||
ValueConditionBlueprint {
|
||||
override final string toString() {
|
||||
result = "compiler generated condition (" + generatedBy.toString() + ")"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Contains an abstract class, which is the super class of all the classes that represent compiler
|
||||
* generated declarations. It extends the blueprint 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.TranslatedDeclarationBlueprint
|
||||
private import TranslatedCompilerGeneratedElement
|
||||
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
|
||||
abstract class TranslatedCompilerGeneratedDeclaration extends LocalVariableDeclarationBlueprint,
|
||||
TranslatedCompilerGeneratedElement {
|
||||
override final string toString() {
|
||||
result = "compiler generated declaration (" + generatedBy.toString() + ")"
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
result = LocalVariableDeclarationBlueprint.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) {
|
||||
LocalVariableDeclarationBlueprint.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 = LocalVariableDeclarationBlueprint.super.getInstructionSuccessor(tag, kind) or
|
||||
(
|
||||
tag = InitializerStoreTag() and
|
||||
result = getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
OperandTag operandTag) {
|
||||
result = LocalVariableDeclarationBlueprint.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,26 @@
|
||||
/**
|
||||
* The abstract super class of every `TranslatedCompilerX` class. It has one member field, `generatedBy`,
|
||||
* which represents the element that generated the compiler generated element.
|
||||
*/
|
||||
|
||||
import csharp
|
||||
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 {
|
||||
// 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() + ")"
|
||||
}
|
||||
|
||||
override final Callable getFunction() {
|
||||
result = generatedBy.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override final Language::AST getAST() {
|
||||
result = generatedBy
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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.TranslatedExprBlueprint
|
||||
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
|
||||
|
||||
abstract class TranslatedCompilerGeneratedExpr extends TranslatedCompilerGeneratedElement,
|
||||
TranslatedExprBlueprint {
|
||||
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 {
|
||||
override final string toString() {
|
||||
result = "compiler generated stmt (" + generatedBy.toString() + ")"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user