зеркало из https://github.com/github/codeql.git
Arrays fixed, simple variable initialization fixed.
Correct code is now generated for array initialization and element access. Created a new binary Opcode, `IndexedElementAddress`, used to get the address of an array element, similar to how CIL does it. Fixed simple variable initialization.
This commit is contained in:
Родитель
2a41e7b5c0
Коммит
26bf7e116d
|
@ -41,6 +41,7 @@ private newtype TOpcode =
|
|||
TDynamicCastToVoid() or
|
||||
TVariableAddress() or
|
||||
TFieldAddress() or
|
||||
TIndexedElementAddress() or
|
||||
TFunctionAddress() or
|
||||
TConstant() or
|
||||
TStringConstant() or
|
||||
|
@ -187,6 +188,7 @@ module Opcode {
|
|||
class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { override final string toString() { result = "DynamicCastToVoid" } }
|
||||
class VariableAddress extends Opcode, TVariableAddress { override final string toString() { result = "VariableAddress" } }
|
||||
class FieldAddress extends UnaryOpcode, TFieldAddress { override final string toString() { result = "FieldAddress" } }
|
||||
class IndexedElementAddress extends BinaryOpcode, TIndexedElementAddress { override final string toString() { result = "IndexedElementAddress" } }
|
||||
class FunctionAddress extends Opcode, TFunctionAddress { override final string toString() { result = "FunctionAddress" } }
|
||||
class Constant extends Opcode, TConstant { override final string toString() { result = "Constant" } }
|
||||
class StringConstant extends Opcode, TStringConstant { override final string toString() { result = "StringConstant" } }
|
||||
|
|
|
@ -1782,3 +1782,25 @@ class BuiltInInstruction extends Instruction {
|
|||
getOpcode() instanceof BuiltInOpcode
|
||||
}
|
||||
}
|
||||
|
||||
class IndexedElementInstruction extends Instruction {
|
||||
ArrayAccess arrAccess;
|
||||
|
||||
IndexedElementInstruction() {
|
||||
arrAccess = Construction::getInstructionArrayAccess(this)
|
||||
}
|
||||
|
||||
override final string getImmediateString() {
|
||||
result = arrAccess.toString()
|
||||
}
|
||||
|
||||
final ArrayAccess getArrayAccess() {
|
||||
result = arrAccess
|
||||
}
|
||||
}
|
||||
|
||||
class IndexedElementAddressInstruction extends VariableInstruction {
|
||||
IndexedElementAddressInstruction() {
|
||||
getOpcode() instanceof Opcode::IndexedElementAddress
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ class PrintIRConfiguration extends TPrintIRConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
private predicate shouldPrintCallable(Callable func) {
|
||||
private predicate shouldPrintFunction(Callable func) {
|
||||
exists(PrintIRConfiguration config |
|
||||
config.shouldPrintFunction(func)
|
||||
)
|
||||
|
@ -32,8 +32,8 @@ private predicate shouldPrintCallable(Callable func) {
|
|||
* Override of `IRConfiguration` to only create IR for the functions that are to be dumped.
|
||||
*/
|
||||
private class FilteredIRConfiguration extends IRConfiguration {
|
||||
override predicate shouldCreateIRForCallable(Callable func) {
|
||||
shouldPrintCallable(func)
|
||||
override predicate shouldCreateIRForFunction(Callable func) {
|
||||
shouldPrintFunction(func)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,13 +51,13 @@ private string getAdditionalBlockProperty(IRBlock block, string key) {
|
|||
|
||||
private newtype TPrintableIRNode =
|
||||
TPrintableIRFunction(IRFunction irFunc) {
|
||||
shouldPrintCallable(irFunc.getCallable())
|
||||
shouldPrintFunction(irFunc.getFunction())
|
||||
} or
|
||||
TPrintableIRBlock(IRBlock block) {
|
||||
shouldPrintCallable(block.getEnclosingFunction())
|
||||
shouldPrintFunction(block.getEnclosingFunction())
|
||||
} or
|
||||
TPrintableInstruction(Instruction instr) {
|
||||
shouldPrintCallable(instr.getEnclosingCallable())
|
||||
shouldPrintFunction(instr.getEnclosingFunction())
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,7 +132,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction {
|
|||
|
||||
override string getLabel() {
|
||||
// TODO: C++ USED THE PRINT MODULE, NOT SURE TOsTRING DOES THE JOB
|
||||
result = irFunc.getCallable().toString()
|
||||
result = irFunc.getFunction().toString()
|
||||
}
|
||||
|
||||
override int getOrder() {
|
||||
|
|
|
@ -215,6 +215,11 @@ cached private module Cached {
|
|||
result = element.getInstructionField(tag)
|
||||
)
|
||||
}
|
||||
|
||||
cached ArrayAccess getInstructionArrayAccess(Instruction instruction) {
|
||||
result = getInstructionTranslatedElement(instruction).getInstructionArrayAccess(
|
||||
getInstructionTag(instruction))
|
||||
}
|
||||
|
||||
cached Callable getInstructionFunction(Instruction instruction) {
|
||||
result = getInstructionTranslatedElement(instruction)
|
||||
|
|
|
@ -166,8 +166,15 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali
|
|||
result = getVariableType(getVariable())
|
||||
}
|
||||
|
||||
// TODO: All declarations which use an initializer will need a special case here
|
||||
private TranslatedInitialization getInitialization() {
|
||||
result = getTranslatedInitialization(getVariable().getInitializer())
|
||||
// First complex initializations
|
||||
if (getVariable().getInitializer() instanceof ArrayCreation) then
|
||||
result = getTranslatedInitialization(getVariable().getInitializer().(ArrayCreation).getInitializer())
|
||||
else if (getVariable().getInitializer() instanceof ObjectCreation) then
|
||||
result = getTranslatedInitialization(getVariable().getInitializer().(ObjectCreation).getInitializer())
|
||||
else // then the simple variable initialization
|
||||
result = getTranslatedInitialization(getVariable().getInitializer())
|
||||
}
|
||||
|
||||
private predicate hasUninitializedInstruction() {
|
||||
|
|
|
@ -183,7 +183,9 @@ newtype TTranslatedElement =
|
|||
// A separate element to handle the lvalue-to-rvalue conversion step of an
|
||||
// expression.
|
||||
TTranslatedLoad(Expr expr) {
|
||||
expr instanceof AssignableRead
|
||||
// TODO: Revisit and make sure Loads are only used when needed
|
||||
expr instanceof AssignableRead and
|
||||
not (expr.getParent() instanceof ArrayAccess)
|
||||
} or
|
||||
// An expression most naturally translated as control flow.
|
||||
TTranslatedNativeCondition(Expr expr) {
|
||||
|
@ -218,13 +220,25 @@ newtype TTranslatedElement =
|
|||
TTranslatedInitialization(Expr expr) {
|
||||
not ignoreExpr(expr) and
|
||||
(
|
||||
exists(ObjectInitializer objInit | objInit = expr) or
|
||||
exists(MemberInitializer memInit | memInit = expr) or
|
||||
exists(CollectionInitializer colInit | colInit = expr) or
|
||||
exists(ReturnStmt returnStmt | returnStmt.getExpr() = expr) or
|
||||
exists(ElementInitializer elInit | elInit = expr) or
|
||||
exists(ThrowExpr throw | throw.getExpr() = expr) or
|
||||
// Because of the implementation of initializations in C#,
|
||||
// we deal with all the types of initialization separately.
|
||||
// First only simple local variable initialization (ie. `int x = 0`)
|
||||
exists(LocalVariableDeclAndInitExpr lvInit |
|
||||
lvInit.getInitializer() = expr and
|
||||
not expr instanceof ArrayCreation and
|
||||
not expr instanceof ObjectCreation) or
|
||||
|
||||
// Then treat complex ones
|
||||
exists(ArrayInitializer arrInit | arrInit = expr) or
|
||||
exists(ObjectInitializer objInit | objInit = expr) or
|
||||
|
||||
// Then treat the inner expressions of initializers
|
||||
exists(ObjectInitializer objInit | objInit.getAChildExpr() = expr) or
|
||||
exists(MemberInitializer memInit | memInit.getAChildExpr() = expr) or
|
||||
exists(CollectionInitializer colInit | colInit.getAChildExpr() = expr) or
|
||||
exists(ReturnStmt returnStmt | returnStmt.getExpr() = expr) or
|
||||
exists(ThrowExpr throw | throw.getExpr() = expr) or
|
||||
exists(ArrayInitializer arrInit | arrInit.getAChildExpr() = expr) or
|
||||
exists(LambdaExpr lambda | lambda.getSourceDeclaration() = expr) or
|
||||
exists(AnonymousMethodExpr anonMethExpr | anonMethExpr.getSourceDeclaration() = expr)
|
||||
)
|
||||
|
@ -492,6 +506,12 @@ abstract class TranslatedElement extends TTranslatedElement {
|
|||
* `Field` for that instruction.
|
||||
*/
|
||||
Field getInstructionField(InstructionTag tag) { none() }
|
||||
|
||||
/**
|
||||
* If the instruction specified by `tag` is an `IndexedElementInstruction`,
|
||||
* gets the `ArrayAccess` of that instruction.
|
||||
*/
|
||||
ArrayAccess getInstructionArrayAccess(InstructionTag tag) { none() }
|
||||
|
||||
/**
|
||||
* If the instruction specified by `tag` is a `ConstantValueInstruction`, gets
|
||||
|
|
|
@ -98,7 +98,10 @@ abstract class TranslatedCoreExpr extends TranslatedExpr {
|
|||
* then a load.
|
||||
*/
|
||||
override final predicate producesExprResult() {
|
||||
not (expr instanceof AssignableRead)
|
||||
// TODO: When the compatibility layer is in place,
|
||||
// create a special class for the following cases
|
||||
not (expr instanceof AssignableRead) or
|
||||
expr.getParent() instanceof ArrayAccess
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -644,9 +647,9 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
|||
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
|
||||
Type resultType, boolean isLValue) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::PointerAdd and
|
||||
resultType = getBaseOperand().getResultType() and
|
||||
isLValue = false
|
||||
opcode instanceof Opcode::IndexedElementAddress and
|
||||
resultType = getResultType() and
|
||||
isLValue = true
|
||||
}
|
||||
|
||||
override Instruction getInstructionOperand(InstructionTag tag,
|
||||
|
@ -670,11 +673,14 @@ class TranslatedArrayExpr extends TranslatedNonConstantExpr {
|
|||
}
|
||||
|
||||
private TranslatedExpr getBaseOperand() {
|
||||
result = getTranslatedExpr(expr.getChild(0))
|
||||
exists (Element el |
|
||||
expr = el.getParent() and
|
||||
el instanceof VariableAccess and
|
||||
result = getTranslatedExpr(el))
|
||||
}
|
||||
|
||||
private TranslatedExpr getOffsetOperand() {
|
||||
result = getTranslatedExpr(expr.getChild(1))
|
||||
result = getTranslatedExpr(expr.getChild(0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -822,7 +828,10 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr {
|
|||
|
||||
class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
|
||||
TranslatedNonFieldVariableAccess() {
|
||||
not expr instanceof FieldAccess
|
||||
// TODO: Make sure those are enough and correct
|
||||
not expr instanceof FieldAccess and
|
||||
// Init should take care of this access (check with cpp)
|
||||
(not expr.getParent() instanceof LocalVariableDeclAndInitExpr)
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
|
|
|
@ -153,6 +153,9 @@ class TranslatedArrayListInitialization extends TranslatedListInitialization {
|
|||
*/
|
||||
abstract class TranslatedDirectInitialization extends TranslatedInitialization {
|
||||
TranslatedDirectInitialization() {
|
||||
// TODO: Make sure this is complete and correct
|
||||
not expr instanceof ArrayInitializer and
|
||||
not expr instanceof ObjectInitializer and
|
||||
not expr instanceof CollectionInitializer
|
||||
}
|
||||
|
||||
|
@ -473,7 +476,7 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
|||
) or
|
||||
(
|
||||
tag = getElementAddressTag() and
|
||||
opcode instanceof Opcode::PointerAdd and
|
||||
opcode instanceof Opcode::IndexedElementAddress and
|
||||
resultType = getElementType() and
|
||||
isLValue = true
|
||||
)
|
||||
|
@ -519,7 +522,7 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
|||
}
|
||||
|
||||
final Type getElementType() {
|
||||
result = initList.getType().(ArrayType).getElementType()
|
||||
result = initList.getAnElement().getType()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
using System;
|
||||
|
||||
public class array_init_and_access {
|
||||
public static void f() {
|
||||
int[] arr = { 101, 102 };
|
||||
arr[1] = 5;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,29 @@
|
|||
array_acc.cs:
|
||||
# 4| f
|
||||
# 4| Block 0
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(lval<array_init_and_access>) = InitializeThis :
|
||||
# 5| r0_4(lval<Int32[]>) = VariableAddress[arr] :
|
||||
# 5| mu0_5(Int32[]) = Uninitialized[arr] : &:r0_4
|
||||
# 5| r0_6(Int32) = Constant[0] :
|
||||
# 5| r0_7(lval<Int32>) = IndexedElementAddress : r0_4, r0_6
|
||||
# 5| r0_8(Int32) = Constant[101] :
|
||||
# 5| mu0_9(Int32) = Store : &:r0_7, r0_8
|
||||
# 5| r0_10(Int32) = Constant[1] :
|
||||
# 5| r0_11(lval<Int32>) = IndexedElementAddress : r0_4, r0_10
|
||||
# 5| r0_12(Int32) = Constant[102] :
|
||||
# 5| mu0_13(Int32) = Store : &:r0_11, r0_12
|
||||
# 6| r0_14(Int32) = Constant[5] :
|
||||
# 6| r0_15(lval<Int32[]>) = VariableAddress[arr] :
|
||||
# 6| r0_16(Int32) = Constant[1] :
|
||||
# 6| r0_17(lval<Int32>) = IndexedElementAddress : r0_15, r0_16
|
||||
# 6| mu0_18(Int32) = Store : &:r0_17, r0_14
|
||||
# 4| v0_19(Void) = ReturnVoid :
|
||||
# 4| v0_20(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_21(Void) = ExitFunction :
|
||||
|
||||
simple_function.cs:
|
||||
# 4| f
|
||||
# 4| Block 0
|
||||
|
@ -16,26 +42,22 @@ simple_function.cs:
|
|||
variables.cs:
|
||||
# 4| f
|
||||
# 4| Block 0
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(lval<test_variables>) = InitializeThis :
|
||||
# 5| r0_4(lval<Int32>) = VariableAddress[x] :
|
||||
# 5| mu0_5(Int32) = Uninitialized[x] : &:r0_4
|
||||
# 5| r0_6(lval<Int32>) = VariableAddress[y] :
|
||||
# 5| mu0_7(Int32) = Uninitialized[y] : &:r0_6
|
||||
# 6| r0_8(Int32) = Constant[0] :
|
||||
# 6| r0_9(lval<Int32>) = VariableAddress[y] :
|
||||
# 6| mu0_10(Int32) = Store : &:r0_9, r0_8
|
||||
# 7| r0_11(lval<Int32>) = VariableAddress[y] :
|
||||
# 7| r0_12(Int32) = Load : &:r0_11, ~mu0_2
|
||||
# 7| r0_13(lval<Int32>) = VariableAddress[x] :
|
||||
# 7| mu0_14(Int32) = Store : &:r0_13, r0_12
|
||||
# 8| r0_15(lval<Int32>) = VariableAddress[#return] :
|
||||
# 8| r0_16(lval<Int32>) = VariableAddress[x] :
|
||||
# 8| r0_17(Int32) = Load : &:r0_16, ~mu0_2
|
||||
# 8| mu0_18(Int32) = Store : &:r0_15, r0_17
|
||||
# 4| r0_19(lval<Int32>) = VariableAddress[#return] :
|
||||
# 4| v0_20(Void) = ReturnValue : &:r0_19, ~mu0_2
|
||||
# 4| v0_21(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_22(Void) = ExitFunction :
|
||||
# 4| v0_0(Void) = EnterFunction :
|
||||
# 4| mu0_1(Object) = AliasedDefinition :
|
||||
# 4| mu0_2(Object) = UnmodeledDefinition :
|
||||
# 4| r0_3(lval<test_variables>) = InitializeThis :
|
||||
# 5| r0_4(lval<Int32>) = VariableAddress[x] :
|
||||
# 5| mu0_5(Int32) = Uninitialized[x] : &:r0_4
|
||||
# 5| r0_6(lval<Int32>) = VariableAddress[y] :
|
||||
# 5| r0_7(Int32) = Constant[5] :
|
||||
# 5| mu0_8(Int32) = Store : &:r0_6, r0_7
|
||||
# 6| r0_9(Int32) = Constant[4] :
|
||||
# 6| r0_10(lval<Int32>) = VariableAddress[x] :
|
||||
# 6| mu0_11(Int32) = Store : &:r0_10, r0_9
|
||||
# 7| r0_12(lval<Int32>) = VariableAddress[y] :
|
||||
# 7| r0_13(Int32) = Load : &:r0_12, ~mu0_2
|
||||
# 7| r0_14(lval<Int32>) = VariableAddress[x] :
|
||||
# 7| mu0_15(Int32) = Store : &:r0_14, r0_13
|
||||
# 4| v0_16(Void) = ReturnVoid :
|
||||
# 4| v0_17(Void) = UnmodeledUse : mu*
|
||||
# 4| v0_18(Void) = ExitFunction :
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
|
||||
public class test_simple_function {
|
||||
public static int f() {
|
||||
return 0;
|
||||
}
|
||||
public static int f() {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
import default
|
||||
import semmle.code.csharp.ir.PrintIR
|
||||
//import semmle.code.csharp.ir.implementation.raw.Instruction
|
||||
|
||||
//query predicate blockSuccessors(IRBlock pred, IRBlock succ) { succ = pred.getASuccessor() }
|
||||
//
|
||||
//query predicate instructions(IRFunction func, IRBlock block, Instruction instruction) {
|
||||
// func = block.getEnclosingIRFunction() and
|
||||
// instruction.getBlock() = block
|
||||
//}
|
||||
//
|
||||
//from Instruction i, StoreInstruction si
|
||||
//where i = si.getASuccessor()
|
||||
//select i, si
|
||||
//
|
||||
//from Instruction i1, Instruction i2
|
||||
//where i1 = i2.getASuccessor() and i1.getAST().fromSource()
|
||||
//select "Instruction '" + i1 + "' successor to '" + i2 + "'"
|
||||
|
||||
//from IRBlock bl, Instruction instr
|
||||
//where instr.getBlock() = bl
|
||||
//select bl, instr
|
|
@ -1,10 +1,9 @@
|
|||
using System;
|
||||
|
||||
public class test_variables {
|
||||
public static int f() {
|
||||
int x, y;
|
||||
y = 0;
|
||||
x = y;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
public static void f() {
|
||||
int x, y = 5;
|
||||
x = 4;
|
||||
x = y;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче