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:
Andrei Diaconu 2019-07-22 15:03:49 +01:00 коммит произвёл AndreiDiaconu1
Родитель 2a41e7b5c0
Коммит 26bf7e116d
13 изменённых файлов: 154 добавлений и 79 удалений

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

@ -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;
}
}