Added C# implementation

This commit is contained in:
AndreiDiaconu1
2019-09-23 15:27:15 +01:00
parent 1dab4e0e26
commit 17e6b80a34
24 changed files with 163 additions and 137 deletions

View File

@@ -3,4 +3,4 @@
* publicly as the "IR".
*/
import implementation.raw.IR
import implementation.unaliased_ssa.IR

View File

@@ -15,5 +15,7 @@ class IRConfiguration extends TIRConfiguration {
/**
* Holds if IR should be created for callable `callable`. By default, holds for all callables.
*/
predicate shouldCreateIRForFunction(Callable callable) { any() }
predicate shouldCreateIRForFunction(Callable callable) {
callable.getLocation().getFile().getExtension() = "cs"
}
}

View File

@@ -5,4 +5,4 @@
* @kind graph
*/
import implementation.raw.PrintIR
import implementation.unaliased_ssa.PrintIR

View File

@@ -1 +1 @@
import implementation.raw.PrintIR
import implementation.unaliased_ssa.PrintIR

View File

@@ -1 +1 @@
import implementation.raw.gvn.ValueNumbering
import implementation.unaliased_ssa.gvn.ValueNumbering

View File

@@ -1,5 +1,5 @@
private import internal.ConstantAnalysisInternal
private import semmle.code.cpp.ir.internal.IntegerPartial
private import semmle.code.csharp.ir.internal.IntegerPartial
private import IR
language[monotonicAggregates]

View File

@@ -1,5 +1,5 @@
private import internal.ConstantAnalysisInternal
private import semmle.code.cpp.ir.internal.IntegerConstant
private import semmle.code.csharp.ir.internal.IntegerConstant
private import ConstantAnalysis
import IR

View File

@@ -1 +1 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR
import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR

View File

@@ -1,5 +1,5 @@
private import internal.ValueNumberingInternal
private import cpp
private import csharp
private import IR
/**

View File

@@ -1 +1 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR
import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as IR

View File

@@ -1,8 +1,7 @@
private import AliasAnalysisInternal
private import cpp
private import csharp
private import InputIR
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
private import semmle.code.cpp.models.interfaces.Alias
private import semmle.code.csharp.ir.internal.IntegerConstant as Ints
private class IntValue = Ints::IntValue;
@@ -26,17 +25,16 @@ string getBitOffsetString(IntValue bitOffset) {
else result = "+?"
}
///**
// * Gets the offset of field `field` in bits.
// */
//private IntValue getFieldBitOffset(Field field) {
// if field instanceof BitField
// then result = Ints::add(Ints::mul(field.getByteOffset(), 8), field.(BitField).getBitOffset())
// else result = Ints::mul(field.getByteOffset(), 8)
//}
/**
* Gets the offset of field `field` in bits.
*/
private IntValue getFieldBitOffset(Field field) {
if field instanceof BitField
then result = Ints::add(Ints::mul(field.getByteOffset(), 8), field.(BitField).getBitOffset())
else result = Ints::mul(field.getByteOffset(), 8)
}
/**
* Holds if the operand `tag` of instruction `instr` is used in a way that does
* Holds if the operand `operand` of instruction `instr` is used in a way that does
* not result in any address held in that operand from escaping beyond the
* instruction.
*/
@@ -53,21 +51,18 @@ private predicate operandIsConsumedWithoutEscaping(Operand operand) {
or
// Neither operand of a PointerDiff escapes.
instr instanceof PointerDiffInstruction
or
// Converting an address to a `bool` does not escape the address.
instr.(ConvertInstruction).getResultType() instanceof BoolType
)
)
or
// Some standard function arguments never escape
isNeverEscapesArgument(operand)
// or
// // Some standard function arguments never escape
// isNeverEscapesArgument(operand)
}
private predicate operandEscapesDomain(Operand operand) {
not operandIsConsumedWithoutEscaping(operand) and
not operandIsPropagated(operand, _) and
not isArgumentForParameter(_, operand, _) and
not isOnlyEscapesViaReturnArgument(operand) and
// not isOnlyEscapesViaReturnArgument(operand) and
not operand.getUse() instanceof ReturnValueInstruction and
not operand instanceof PhiInputOperand
}
@@ -99,7 +94,7 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
}
/**
* Holds if any address held in operand `tag` of instruction `instr` is
* Holds if any address held in operand `operand` of instruction `instr` is
* propagated to the result of `instr`, offset by the number of bits in
* `bitOffset`. If the address is propagated, but the offset is not known to be
* a constant, then `bitOffset` is unknown.
@@ -108,29 +103,36 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
exists(Instruction instr |
instr = operand.getUse() and
(
// Converting to a non-virtual base class adds the offset of the base class.
exists(ConvertToBaseInstruction convert |
convert = instr and
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
)
or
// Converting to a derived class subtracts the offset of the base class.
exists(ConvertToDerivedInstruction convert |
convert = instr and
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
)
or
// Converting to a virtual base class adds an unknown offset.
instr instanceof ConvertToVirtualBaseInstruction and
bitOffset = Ints::unknown()
or
// REVIEW: See the REVIEW comment bellow
// // Converting to a non-virtual base class adds the offset of the base class.
// exists(ConvertToBaseInstruction convert |
// convert = instr and
// bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
// )
// or
// // Converting to a derived class subtracts the offset of the base class.
// exists(ConvertToDerivedInstruction convert |
// convert = instr and
// bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
// )
// or
// // Converting to a virtual base class adds an unknown offset.
// instr instanceof ConvertToVirtualBaseInstruction and
// bitOffset = Ints::unknown()
// or
// REVIEW: In the C# IR, we should ignore the above types of conversion all together,
// since first of all they do not provide correct information (nothing is known
// for sure about heap allocated objects) and second of all even if we create a
// virtual memory model for the IR I don't think such conversions provide any meaningful
// information;
// Conversion to another pointer type propagates the source address.
// REVIEW: Is this needed?
exists(ConvertInstruction convert, Type resultType |
convert = instr and
resultType = convert.getResultType() and
(
resultType instanceof PointerType or
resultType instanceof Class //REVIEW: Remove when all glvalues are pointers
resultType instanceof RefType
) and
bitOffset = 0
)
@@ -139,15 +141,15 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
// the address with an offset.
bitOffset = getPointerBitOffset(instr.(PointerOffsetInstruction))
or
// Computing a field address from a pointer propagates the address plus the
// offset of the field.
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField())
or
// or
// // Computing a field address from a pointer propagates the address plus the
// // offset of the field.
// bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField())
// A copy propagates the source value.
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
or
// Some functions are known to propagate an argument
isAlwaysReturnedArgument(operand) and bitOffset = 0
// or
// // Some functions are known to propagate an argument
// isAlwaysReturnedArgument(operand) and bitOffset = 0
)
)
}
@@ -167,8 +169,8 @@ private predicate operandEscapesNonReturn(Operand operand) {
)
)
or
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
or
// or
// isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
operand instanceof PhiInputOperand and
resultEscapesNonReturn(operand.getUse())
or
@@ -190,8 +192,8 @@ private predicate operandMayReachReturn(Operand operand) {
// The address is returned
operand.getUse() instanceof ReturnValueInstruction
or
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
or
// or
// isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
operand instanceof PhiInputOperand and
resultMayReachReturn(operand.getUse())
}
@@ -216,49 +218,50 @@ private predicate operandReturned(Operand operand, IntValue bitOffset) {
operand.getUse() instanceof ReturnValueInstruction and
bitOffset = 0
or
isOnlyEscapesViaReturnArgument(operand) and
// isOnlyEscapesViaReturnArgument(operand) and
resultReturned(operand.getUse(), _) and
bitOffset = Ints::unknown()
}
private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) {
exists(Function f |
exists(Callable c |
ci = operand.getUse() and
f = ci.getStaticCallTarget() and
c = ci.getStaticCallTarget() and
(
init.(InitializeParameterInstruction).getParameter() = f
init.(InitializeParameterInstruction).getParameter() = c
.getParameter(operand.(PositionalArgumentOperand).getIndex())
or
init instanceof InitializeThisInstruction and
init.getEnclosingFunction() = f and
init.getEnclosingFunction() = c and
operand instanceof ThisArgumentOperand
) and
not f.isVirtual() and
not f instanceof AliasFunction
)
}
private predicate isAlwaysReturnedArgument(Operand operand) {
exists(AliasFunction f |
f = operand.getUse().(CallInstruction).getStaticCallTarget() and
f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex())
)
}
private predicate isOnlyEscapesViaReturnArgument(Operand operand) {
exists(AliasFunction f |
f = operand.getUse().(CallInstruction).getStaticCallTarget() and
f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex())
)
}
private predicate isNeverEscapesArgument(Operand operand) {
exists(AliasFunction f |
f = operand.getUse().(CallInstruction).getStaticCallTarget() and
f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex())
) // and
// not f.isVirtual() and
// not f instanceof AliasFunction
)
}
// REVIEW: Those three predicates are used to model the behaviour of C++ library functions
// for which the code was not accessible, so we should ignore them
//private predicate isAlwaysReturnedArgument(Operand operand) {
// exists(AliasFunction f |
// f = operand.getUse().(CallInstruction).getStaticCallTarget() and
// f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex())
// )
//}
//
//private predicate isOnlyEscapesViaReturnArgument(Operand operand) {
// exists(AliasFunction f |
// f = operand.getUse().(CallInstruction).getStaticCallTarget() and
// f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex())
// )
//}
//
//private predicate isNeverEscapesArgument(Operand operand) {
// exists(AliasFunction f |
// f = operand.getUse().(CallInstruction).getStaticCallTarget() and
// f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex())
// )
//}
private predicate resultReturned(Instruction instr, IntValue bitOffset) {
operandReturned(instr.getAUse(), bitOffset)
}

View File

@@ -1 +1 @@
import semmle.code.cpp.ir.implementation.raw.IR as InputIR
import semmle.code.csharp.ir.implementation.raw.IR as InputIR

View File

@@ -1 +1 @@
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind

View File

@@ -1,2 +1,2 @@
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind

View File

@@ -1,2 +1,2 @@
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
import SSAConstruction as Construction

View File

@@ -1,4 +1,4 @@
import semmle.code.cpp.ir.implementation.TempVariableTag as TempVariableTag
import semmle.code.cpp.ir.internal.IRUtilities as IRUtilities
import semmle.code.cpp.ir.internal.TempVariableTag as TTempVariableTag
import semmle.code.cpp.ir.implementation.internal.TIRVariable as TIRVariable
import semmle.code.csharp.ir.implementation.TempVariableTag as TempVariableTag
import semmle.code.csharp.ir.internal.IRUtilities as IRUtilities
import semmle.code.csharp.ir.internal.TempVariableTag as TTempVariableTag
import semmle.code.csharp.ir.implementation.internal.TIRVariable as TIRVariable

View File

@@ -1,4 +1,4 @@
import semmle.code.cpp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.cpp.ir.implementation.Opcode as Opcode
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
import semmle.code.csharp.ir.implementation.EdgeKind as EdgeKind
import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.csharp.ir.implementation.Opcode as Opcode
import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag

View File

@@ -1,3 +1,3 @@
import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.cpp.ir.internal.Overlap as Overlap
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
import semmle.code.csharp.ir.implementation.MemoryAccessKind as MemoryAccessKind
import semmle.code.csharp.ir.internal.Overlap as Overlap
import semmle.code.csharp.ir.implementation.internal.OperandTag as OperandTag

View File

@@ -1 +1 @@
import semmle.code.cpp.ir.IRConfiguration as IRConfiguration
import semmle.code.csharp.ir.IRConfiguration as IRConfiguration

View File

@@ -1,9 +1,9 @@
import SSAConstructionInternal
private import cpp
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.Overlap
private import semmle.code.csharp.ir.implementation.Opcode
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.internal.Overlap
private import NewIR
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
private class OldBlock = Reachability::ReachableBlock;
@@ -18,7 +18,7 @@ private module Cached {
}
cached
predicate functionHasIR(Function func) {
predicate functionHasIR(Language::Function func) {
exists(OldIR::IRFunction irFunc | irFunc.getFunction() = func)
}
@@ -42,7 +42,7 @@ private module Cached {
not oldInstruction instanceof OldIR::PhiInstruction and
hasChiNode(_, oldInstruction)
} or
Unreached(Function function) {
Unreached(Language::Function function) {
exists(OldInstruction oldInstruction |
function = oldInstruction.getEnclosingFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
@@ -50,7 +50,9 @@ private module Cached {
}
cached
predicate hasTempVariable(Function func, Locatable ast, TempVariableTag tag, Type type) {
predicate hasTempVariable(
Language::Function func, Language::AST ast, TempVariableTag tag, Language::Type type
) {
exists(OldIR::IRTempVariable var |
var.getEnclosingFunction() = func and
var.getAST() = ast and
@@ -135,7 +137,7 @@ private module Cached {
}
cached
Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
Language::Type getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |
oldInstruction = getOldInstruction(instr) and
oldOperand = oldInstruction.getAnOperand() and
@@ -151,7 +153,7 @@ private module Cached {
oldOperand = oldInstruction.getAnOperand() and
tag = oldOperand.getOperandTag() and
// Only return a result for operands that need an explicit result size.
oldOperand.getType() instanceof UnknownType and
oldOperand.getType() instanceof Language::UnknownType and
result = oldOperand.getSize()
)
}
@@ -196,20 +198,21 @@ private module Cached {
}
cached
Expr getInstructionConvertedResultExpression(Instruction instruction) {
Language::Expr getInstructionConvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getConvertedResultExpression()
}
cached
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
Language::Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
result = getOldInstruction(instruction).getUnconvertedResultExpression()
}
/**
/*
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
* that node is its successor in the new successor relation, and the Chi node's successors are
* the new instructions generated from the successors of the old instruction
*/
cached
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
if hasChiNode(_, getOldInstruction(instruction))
@@ -252,7 +255,7 @@ private module Cached {
}
cached
Locatable getInstructionAST(Instruction instruction) {
Language::AST getInstructionAST(Instruction instruction) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction)
or
@@ -270,7 +273,7 @@ private module Cached {
}
cached
predicate instructionHasType(Instruction instruction, Type type, boolean isGLValue) {
predicate instructionHasType(Instruction instruction, Language::Type type, boolean isGLValue) {
exists(OldInstruction oldInstruction |
instruction = WrappedInstruction(oldInstruction) and
type = oldInstruction.getResultType() and
@@ -291,7 +294,7 @@ private module Cached {
)
or
instruction = Unreached(_) and
type instanceof VoidType and
type instanceof Language::VoidType and
isGLValue = false
}
@@ -338,12 +341,12 @@ private module Cached {
}
cached
Field getInstructionField(Instruction instruction) {
Language::Field getInstructionField(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
}
cached
Function getInstructionFunction(Instruction instruction) {
Language::Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()
}
@@ -353,19 +356,19 @@ private module Cached {
}
cached
StringLiteral getInstructionStringLiteral(Instruction instruction) {
Language::StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
}
cached
BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction)
.(OldIR::BuiltInOperationInstruction)
.getBuiltInOperation()
}
cached
Type getInstructionExceptionType(Instruction instruction) {
Language::Type getInstructionExceptionType(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::CatchByTypeInstruction).getExceptionType()
}
@@ -377,12 +380,14 @@ private module Cached {
cached
int getInstructionResultSize(Instruction instruction) {
// Only return a result for instructions that needed an explicit result size.
instruction.getResultType() instanceof UnknownType and
instruction.getResultType() instanceof Language::UnknownType and
result = getOldInstruction(instruction).getResultSize()
}
cached
predicate getInstructionInheritance(Instruction instruction, Class baseClass, Class derivedClass) {
predicate getInstructionInheritance(
Instruction instruction, Language::Class baseClass, Language::Class derivedClass
) {
exists(OldIR::InheritanceConversionInstruction oldInstr |
oldInstr = getOldInstruction(instruction) and
baseClass = oldInstr.getBaseClass() and
@@ -834,7 +839,7 @@ module DefUse {
}
/**
* Expose some of the internal predicates to PrintSSA.qll. We do this by publically importing those modules in the
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
* `DebugSSA` module, which is then imported by PrintSSA.
*/
module DebugSSA {

View File

@@ -1,5 +1,5 @@
import semmle.code.cpp.ir.implementation.raw.IR as OldIR
import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
import semmle.code.csharp.ir.implementation.raw.IR as OldIR
import semmle.code.csharp.ir.implementation.raw.internal.reachability.ReachableBlock as Reachability
import semmle.code.csharp.ir.implementation.raw.internal.reachability.Dominance as Dominance
import semmle.code.csharp.ir.implementation.unaliased_ssa.IR as NewIR
import SimpleSSA as Alias

View File

@@ -1,9 +1,9 @@
import AliasAnalysis
private import cpp
private import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
private import semmle.code.cpp.ir.implementation.internal.OperandTag
private import semmle.code.cpp.ir.internal.Overlap
private import csharp
private import semmle.code.csharp.ir.implementation.raw.IR
private import semmle.code.csharp.ir.internal.IntegerConstant as Ints
private import semmle.code.csharp.ir.implementation.internal.OperandTag
private import semmle.code.csharp.ir.internal.Overlap
private class IntValue = Ints::IntValue;

View File

@@ -0,0 +1,15 @@
missingOperand
unexpectedOperand
duplicateOperand
missingPhiOperand
missingOperandType
instructionWithoutSuccessor
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
operandAcrossFunctions
instructionWithoutUniqueBlock
containsLoopOfForwardEdges
lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition

View File

@@ -0,0 +1 @@
semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.ql