C#: Port `TInstruction`-sharing support from C++

This updates C#'s IR to share `TInstruction` across stages the same way C++ does. The only interesting part is that, since we have not yet ported full alias analysis to C#, I stubbed out the required parts of the aliased SSA interface in `AliasedSSAStub.qll`.
This commit is contained in:
Dave Bartolomeo 2020-06-03 13:52:19 -04:00
Родитель e65a5c921e
Коммит bbadf4b4bb
15 изменённых файлов: 298 добавлений и 102 удалений

Просмотреть файл

@ -96,10 +96,18 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll"
],
"IR IRFunctionBase": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/internal/IRFunctionBase.qll"
],
"IR Operand Tag": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll"
],
"IR TInstruction":[
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TInstruction.qll"
],
"IR TIRVariable":[
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll"
@ -292,6 +300,10 @@
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll"
],
"C# IR IRFunctionImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRFunctionImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll"
],
"C# IR IRVariableImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll"

Просмотреть файл

@ -0,0 +1,21 @@
/**
* Provides a stub implementation of the required aliased SSA interface until we implement aliased
* SSA construction for C#.
*/
private import IRFunctionBase
private import TInstruction
module SSA {
class MemoryLocation = boolean;
predicate hasPhiInstruction(
IRFunctionBase irFunc, TRawInstruction blockStartInstr, MemoryLocation memoryLocation
) {
none()
}
predicate hasChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { none() }
predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() }
}

Просмотреть файл

@ -0,0 +1,26 @@
/**
* Provides a base class, `IRFunctionBase`, for the stage-independent portions of `IRFunction`.
*/
private import IRFunctionBaseInternal
private newtype TIRFunction =
MkIRFunction(Language::Function func) { IRConstruction::Raw::functionHasIR(func) }
/**
* The IR for a function. This base class contains only the predicates that are the same between all
* phases of the IR. Each instantiation of `IRFunction` extends this class.
*/
class IRFunctionBase extends TIRFunction {
Language::Function func;
IRFunctionBase() { this = MkIRFunction(func) }
/** Gets a textual representation of this element. */
final string toString() { result = "IR: " + func.toString() }
/** Gets the function whose IR is represented. */
final Language::Function getFunction() { result = func }
/** Gets the location of the function. */
final Language::Location getLocation() { result = func.getLocation() }
}

Просмотреть файл

@ -0,0 +1,2 @@
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as IRConstruction

Просмотреть файл

@ -1,5 +1,5 @@
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as Construction
import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction::Raw as Construction
private import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag_
module Imports {

Просмотреть файл

@ -0,0 +1,101 @@
private import TInstructionInternal
private import IRFunctionBase
private import TInstructionImports as Imports
private import Imports::IRType
private import Imports::Opcode
/**
* An IR instruction. `TInstruction` is shared across all phases of the IR. There are individual
* branches of this type for instructions created directly from the AST (`TRawInstruction`) and for
* instructions added by each stage of SSA construction (`T*PhiInstruction`, `T*ChiInstruction`,
* `T*UnreachedInstruction`). Each stage then defines a `TStageInstruction` type that is a union of
* all of the branches that can appear in that particular stage. The public `Instruction` class for
* each phase extends the `TStageInstruction` type for that stage.
*/
newtype TInstruction =
TRawInstruction(
IRFunctionBase irFunc, Opcode opcode, Language::AST ast,
IRConstruction::Raw::InstructionTag1 tag1, IRConstruction::Raw::InstructionTag2 tag2
) {
IRConstruction::Raw::hasInstruction(irFunc.getFunction(), opcode, ast, tag1, tag2)
} or
TUnaliasedSSAPhiInstruction(
IRFunctionBase irFunc, TRawInstruction blockStartInstr,
UnaliasedSSA::SSA::MemoryLocation memoryLocation
) {
UnaliasedSSA::SSA::hasPhiInstruction(irFunc, blockStartInstr, memoryLocation)
} or
TUnaliasedSSAChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) { none() } or
TUnaliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
UnaliasedSSA::SSA::hasUnreachedInstruction(irFunc)
} or
TAliasedSSAPhiInstruction(
IRFunctionBase irFunc, TRawInstruction blockStartInstr,
AliasedSSA::SSA::MemoryLocation memoryLocation
) {
AliasedSSA::SSA::hasPhiInstruction(irFunc, blockStartInstr, memoryLocation)
} or
TAliasedSSAChiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) {
AliasedSSA::SSA::hasChiInstruction(irFunc, primaryInstruction)
} or
TAliasedSSAUnreachedInstruction(IRFunctionBase irFunc) {
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
}
/**
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
* unaliased SSA stage.
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
* a class alias.
*/
module UnaliasedSSAInstructions {
class TPhiInstruction = TUnaliasedSSAPhiInstruction;
TPhiInstruction phiInstruction(
IRFunctionBase irFunc, TRawInstruction blockStartInstr,
UnaliasedSSA::SSA::MemoryLocation memoryLocation
) {
result = TUnaliasedSSAPhiInstruction(irFunc, blockStartInstr, memoryLocation)
}
class TChiInstruction = TUnaliasedSSAChiInstruction;
TChiInstruction chiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) {
result = TUnaliasedSSAChiInstruction(irFunc, primaryInstruction)
}
class TUnreachedInstruction = TUnaliasedSSAUnreachedInstruction;
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TUnaliasedSSAUnreachedInstruction(irFunc)
}
}
/**
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
* aliased SSA stage.
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
* a class alias.
*/
module AliasedSSAInstructions {
class TPhiInstruction = TAliasedSSAPhiInstruction;
TPhiInstruction phiInstruction(
IRFunctionBase irFunc, TRawInstruction blockStartInstr,
AliasedSSA::SSA::MemoryLocation memoryLocation
) {
result = TAliasedSSAPhiInstruction(irFunc, blockStartInstr, memoryLocation)
}
class TChiInstruction = TAliasedSSAChiInstruction;
TChiInstruction chiInstruction(IRFunctionBase irFunc, TRawInstruction primaryInstruction) {
result = TAliasedSSAChiInstruction(irFunc, primaryInstruction)
}
class TUnreachedInstruction = TAliasedSSAUnreachedInstruction;
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
result = TAliasedSSAUnreachedInstruction(irFunc)
}
}

Просмотреть файл

@ -0,0 +1,2 @@
import semmle.code.csharp.ir.implementation.IRType as IRType
import semmle.code.csharp.ir.implementation.Opcode as Opcode

Просмотреть файл

@ -0,0 +1,4 @@
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction as IRConstruction
import semmle.code.csharp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSSA
import AliasedSSAStub as AliasedSSA

Просмотреть файл

@ -1,6 +1,8 @@
import csharp
import semmle.code.csharp.ir.implementation.raw.IR
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.implementation.internal.IRFunctionBase
private import semmle.code.csharp.ir.implementation.internal.TInstruction
private import semmle.code.csharp.ir.internal.CSharpType
private import semmle.code.csharp.ir.internal.Overlap
private import semmle.code.csharp.ir.internal.TempVariableTag
@ -15,15 +17,33 @@ private import semmle.code.csharp.ir.Util
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
instruction = MkInstruction(result, _)
instruction = TRawInstruction(_, _, _, result, _)
}
InstructionTag getInstructionTag(Instruction instruction) { instruction = MkInstruction(_, result) }
InstructionTag getInstructionTag(Instruction instruction) {
instruction = TRawInstruction(_, _, _, _, result)
}
import Cached
pragma[noinline]
private predicate instructionOrigin(
Instruction instruction, TranslatedElement element, InstructionTag tag
) {
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction)
}
class TStageInstruction = TRawInstruction;
/**
* Provides the portion of the parameterized IR interface that is used to construct the initial
* "raw" stage of the IR. The other stages of the IR do not expose these predicates.
*/
cached
private module Cached {
module Raw {
class InstructionTag1 = TranslatedElement;
class InstructionTag2 = InstructionTag;
cached
predicate functionHasIR(Callable callable) {
exists(getTranslatedFunction(callable)) and
@ -31,10 +51,14 @@ private module Cached {
}
cached
newtype TInstruction =
MkInstruction(TranslatedElement element, InstructionTag tag) {
element.hasInstruction(_, tag, _)
}
predicate hasInstruction(
Callable callable, Opcode opcode, Language::AST ast, TranslatedElement element,
InstructionTag tag
) {
element.hasInstruction(opcode, tag, _) and
ast = element.getAST() and
callable = element.getFunction()
}
cached
predicate hasUserVariable(Callable callable, Variable var, CSharpType type) {
@ -66,16 +90,6 @@ private module Cached {
none()
}
cached
predicate hasModeledMemoryResult(Instruction instruction) { none() }
cached
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
}
cached
Expr getInstructionConvertedResultExpression(Instruction instruction) {
exists(TranslatedExpr translatedExpr |
@ -92,6 +106,93 @@ private module Cached {
)
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction) and
(
result = element.getInstructionVariable(tag) or
result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag)
)
)
}
cached
Field getInstructionField(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionField(tag)
)
}
cached
int getInstructionIndex(Instruction instruction) { none() }
cached
Callable getInstructionFunction(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionFunction(getInstructionTag(instruction))
}
cached
string getInstructionConstantValue(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionConstantValue(getInstructionTag(instruction))
}
cached
CSharpType getInstructionExceptionType(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionExceptionType(getInstructionTag(instruction))
}
cached
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
getInstructionTranslatedElement(instruction)
.getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass)
}
cached
int getInstructionElementSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionElementSize(tag)
)
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() }
}
import Cached
cached
private module Cached {
cached
Opcode getInstructionOpcode(TRawInstruction instr) { instr = TRawInstruction(_, result, _, _, _) }
cached
IRFunctionBase getInstructionEnclosingIRFunction(TRawInstruction instr) {
instr = TRawInstruction(result, _, _, _, _)
}
cached
predicate hasInstruction(TRawInstruction instr) { any() }
cached
predicate hasModeledMemoryResult(Instruction instruction) { none() }
cached
predicate hasConflatedMemoryResult(Instruction instruction) {
instruction instanceof AliasedDefinitionInstruction
or
instruction.getOpcode() instanceof Opcode::InitializeNonLocal
}
cached
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
result =
@ -267,37 +368,6 @@ private module Cached {
.hasInstruction(_, getInstructionTag(instruction), result)
}
cached
Opcode getInstructionOpcode(Instruction instruction) {
getInstructionTranslatedElement(instruction)
.hasInstruction(result, getInstructionTag(instruction), _)
}
cached
IRFunction getInstructionEnclosingIRFunction(Instruction instruction) {
result.getFunction() = getInstructionTranslatedElement(instruction).getFunction()
}
cached
IRVariable getInstructionVariable(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction) and
(
result = element.getInstructionVariable(tag) or
result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag)
)
)
}
cached
Field getInstructionField(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionField(tag)
)
}
cached
ArrayAccess getInstructionArrayAccess(Instruction instruction) {
result =
@ -305,52 +375,6 @@ private module Cached {
.getInstructionArrayAccess(getInstructionTag(instruction))
}
cached
int getInstructionIndex(Instruction instruction) { none() }
cached
Callable getInstructionFunction(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionFunction(getInstructionTag(instruction))
}
cached
string getInstructionConstantValue(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionConstantValue(getInstructionTag(instruction))
}
cached
CSharpType getInstructionExceptionType(Instruction instruction) {
result =
getInstructionTranslatedElement(instruction)
.getInstructionExceptionType(getInstructionTag(instruction))
}
cached
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
getInstructionTranslatedElement(instruction)
.getInstructionInheritance(getInstructionTag(instruction), baseClass, derivedClass)
}
pragma[noinline]
private predicate instructionOrigin(
Instruction instruction, TranslatedElement element, InstructionTag tag
) {
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction)
}
cached
int getInstructionElementSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionElementSize(tag)
)
}
cached
int getInstructionResultSize(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
@ -366,9 +390,6 @@ private module Cached {
result = element.getPrimaryInstructionForSideEffect(tag)
)
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instr) { none() }
}
import CachedForDebugging

Просмотреть файл

@ -0,0 +1 @@
import semmle.code.csharp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

Просмотреть файл

@ -1,3 +1,4 @@
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
import IRConstruction as Construction
import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration
import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction::Raw as Raw

Просмотреть файл

@ -0,0 +1 @@
import semmle.code.csharp.ir.implementation.internal.IRFunctionBase as IRFunctionBase

Просмотреть файл

@ -1,3 +1,4 @@
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
import SSAConstruction as Construction
import semmle.code.csharp.ir.implementation.IRConfiguration as IRConfiguration
import semmle.code.csharp.ir.implementation.raw.internal.IRConstruction::Raw as Raw

Просмотреть файл

@ -1,3 +1,5 @@
import semmle.code.csharp.ir.implementation.Opcode
import semmle.code.csharp.ir.implementation.internal.OperandTag
import semmle.code.csharp.ir.internal.Overlap
import semmle.code.csharp.ir.implementation.Opcode as Opcode
import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag
import semmle.code.csharp.ir.internal.Overlap as Overlap
import semmle.code.csharp.ir.implementation.internal.TInstruction as TInstruction
import semmle.code.csharp.ir.implementation.raw.IR as RawIR

Просмотреть файл

@ -3,4 +3,5 @@ import semmle.code.csharp.ir.implementation.raw.internal.reachability.ReachableB
import semmle.code.csharp.ir.implementation.raw.internal.reachability.Dominance as Dominance
import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as NewIR
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
import semmle.code.csharp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions
import SimpleSSA as Alias