mirror of
https://github.com/github/codeql.git
synced 2026-04-28 02:05:14 +02:00
C# IR: using, checked, unchecked stmts
Added basic support for the using stmt, checked stmt, unchecked stmt Note that the translations do not use the compiler generated element framework and hence they are just rough approximations. For accuracy, in the future their translation should use it.
This commit is contained in:
@@ -89,6 +89,10 @@ private predicate ignoreExprOnly(Expr expr) {
|
||||
or
|
||||
// Ignore the child expression of a goto case stmt
|
||||
expr.getParent() instanceof GotoCaseStmt
|
||||
or
|
||||
// Ignore the expression (that is not a declaration)
|
||||
// that appears in a using block
|
||||
expr.getParent().(UsingBlockStmt).getExpr() = expr
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,6 +182,7 @@ newtype TTranslatedElement =
|
||||
// expression.
|
||||
TTranslatedLoad(Expr expr) {
|
||||
// TODO: Revisit and make sure Loads are only used when needed
|
||||
not ignoreExpr(expr) and
|
||||
expr instanceof AssignableRead and
|
||||
not expr.getParent() instanceof ArrayAccess and
|
||||
not (
|
||||
|
||||
@@ -966,3 +966,114 @@ class TranslatedLockStmt extends TranslatedStmt {
|
||||
result = LockElements::getLockWasTakenDecl(stmt)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should be modeled using the desugaring framework for a
|
||||
// more exact translation.
|
||||
class TranslatedCheckedUncheckedStmt extends TranslatedStmt {
|
||||
TranslatedCheckedUncheckedStmt() {
|
||||
stmt instanceof CheckedStmt or
|
||||
stmt instanceof UncheckedStmt
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = this.getBody() }
|
||||
|
||||
override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() }
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = this.getBody() and
|
||||
result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
private TranslatedElement getBody() {
|
||||
result = getTranslatedStmt(stmt.(CheckedStmt).getBlock()) or
|
||||
result = getTranslatedStmt(stmt.(UncheckedStmt).getBlock())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should be modeled using the desugaring framework for a
|
||||
// more exact translation.
|
||||
class TranslatedUsingBlockStmt extends TranslatedStmt {
|
||||
override UsingBlockStmt stmt;
|
||||
|
||||
override TranslatedElement getChild(int id) {
|
||||
result = getDecl(id)
|
||||
or
|
||||
id = noDecls() and result = this.getBody()
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
if noDecls() > 0
|
||||
then result = this.getDecl(0).getFirstInstruction()
|
||||
else result = this.getBody().getFirstInstruction()
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
exists(int id |
|
||||
child = this.getDecl(id) and
|
||||
id < this.noDecls() - 1 and
|
||||
result = this.getDecl(id + 1).getFirstInstruction()
|
||||
)
|
||||
or
|
||||
child = this.getDecl(this.noDecls() - 1) and result = this.getBody().getFirstInstruction()
|
||||
or
|
||||
child = this.getBody() and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
private TranslatedLocalDeclaration getDecl(int id) {
|
||||
result = getTranslatedLocalDeclaration(stmt.getVariableDeclExpr(id))
|
||||
}
|
||||
|
||||
private int noDecls() { result = count(stmt.getAVariableDeclExpr()) }
|
||||
|
||||
private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getBody()) }
|
||||
}
|
||||
|
||||
// TODO: Should be modeled using the desugaring framework for a
|
||||
// more exact translation.
|
||||
class TranslatedUsingDeclStmt extends TranslatedStmt {
|
||||
override UsingDeclStmt stmt;
|
||||
|
||||
override TranslatedElement getChild(int id) { result = getDecl(id) }
|
||||
|
||||
override Instruction getFirstInstruction() { result = this.getDecl(0).getFirstInstruction() }
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
exists(int id |
|
||||
child = this.getDecl(id) and
|
||||
id < this.noDecls() - 1 and
|
||||
result = this.getDecl(id + 1).getFirstInstruction()
|
||||
)
|
||||
or
|
||||
child = this.getDecl(this.noDecls() - 1) and result = this.getParent().getChildSuccessor(this)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(
|
||||
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
|
||||
|
||||
private TranslatedLocalDeclaration getDecl(int id) {
|
||||
result = getTranslatedLocalDeclaration(stmt.getVariableDeclExpr(id))
|
||||
}
|
||||
|
||||
private int noDecls() { result = count(stmt.getAVariableDeclExpr()) }
|
||||
}
|
||||
|
||||
@@ -1390,6 +1390,103 @@ stmts.cs:
|
||||
#-----| False -> Block 1
|
||||
#-----| True (back edge) -> Block 2
|
||||
|
||||
# 87| System.Void test_stmts.checkedUnchecked()
|
||||
# 87| Block 0
|
||||
# 87| v0_0(Void) = EnterFunction :
|
||||
# 87| mu0_1(null) = AliasedDefinition :
|
||||
# 87| mu0_2(null) = UnmodeledDefinition :
|
||||
# 89| r0_3(glval<Int32>) = VariableAddress[num] :
|
||||
# 89| r0_4(Int32) = Constant[2147483647] :
|
||||
# 89| r0_5(Int32) = Load : &:r0_4, ~mu0_2
|
||||
# 89| mu0_6(Int32) = Store : &:r0_3, r0_5
|
||||
# 92| r0_7(glval<Int32>) = VariableAddress[num] :
|
||||
# 92| r0_8(Int32) = Load : &:r0_7, ~mu0_2
|
||||
# 92| r0_9(Int32) = Constant[1] :
|
||||
# 92| r0_10(Int32) = Add : r0_8, r0_9
|
||||
# 92| r0_11(glval<Int32>) = VariableAddress[num] :
|
||||
# 92| mu0_12(Int32) = Store : &:r0_11, r0_10
|
||||
# 96| r0_13(glval<Int32>) = VariableAddress[num] :
|
||||
# 96| r0_14(Int32) = Load : &:r0_13, ~mu0_2
|
||||
# 96| r0_15(Int32) = Constant[1] :
|
||||
# 96| r0_16(Int32) = Add : r0_14, r0_15
|
||||
# 96| r0_17(glval<Int32>) = VariableAddress[num] :
|
||||
# 96| mu0_18(Int32) = Store : &:r0_17, r0_16
|
||||
# 87| v0_19(Void) = ReturnVoid :
|
||||
# 87| v0_20(Void) = UnmodeledUse : mu*
|
||||
# 87| v0_21(Void) = ExitFunction :
|
||||
|
||||
using.cs:
|
||||
# 7| System.Void UsingStmt.MyDisposable..ctor()
|
||||
# 7| Block 0
|
||||
# 7| v0_0(Void) = EnterFunction :
|
||||
# 7| mu0_1(null) = AliasedDefinition :
|
||||
# 7| mu0_2(null) = UnmodeledDefinition :
|
||||
# 7| r0_3(glval<MyDisposable>) = InitializeThis :
|
||||
# 7| v0_4(Void) = NoOp :
|
||||
# 7| v0_5(Void) = ReturnVoid :
|
||||
# 7| v0_6(Void) = UnmodeledUse : mu*
|
||||
# 7| v0_7(Void) = ExitFunction :
|
||||
|
||||
# 8| System.Void UsingStmt.MyDisposable.DoSomething()
|
||||
# 8| Block 0
|
||||
# 8| v0_0(Void) = EnterFunction :
|
||||
# 8| mu0_1(null) = AliasedDefinition :
|
||||
# 8| mu0_2(null) = UnmodeledDefinition :
|
||||
# 8| r0_3(glval<MyDisposable>) = InitializeThis :
|
||||
# 8| v0_4(Void) = NoOp :
|
||||
# 8| v0_5(Void) = ReturnVoid :
|
||||
# 8| v0_6(Void) = UnmodeledUse : mu*
|
||||
# 8| v0_7(Void) = ExitFunction :
|
||||
|
||||
# 9| System.Void UsingStmt.MyDisposable.Dispose()
|
||||
# 9| Block 0
|
||||
# 9| v0_0(Void) = EnterFunction :
|
||||
# 9| mu0_1(null) = AliasedDefinition :
|
||||
# 9| mu0_2(null) = UnmodeledDefinition :
|
||||
# 9| r0_3(glval<MyDisposable>) = InitializeThis :
|
||||
# 9| v0_4(Void) = NoOp :
|
||||
# 9| v0_5(Void) = ReturnVoid :
|
||||
# 9| v0_6(Void) = UnmodeledUse : mu*
|
||||
# 9| v0_7(Void) = ExitFunction :
|
||||
|
||||
# 12| System.Void UsingStmt.Main()
|
||||
# 12| Block 0
|
||||
# 12| v0_0(Void) = EnterFunction :
|
||||
# 12| mu0_1(null) = AliasedDefinition :
|
||||
# 12| mu0_2(null) = UnmodeledDefinition :
|
||||
# 14| r0_3(glval<MyDisposable>) = VariableAddress[o1] :
|
||||
# 14| r0_4(MyDisposable) = NewObj :
|
||||
# 14| r0_5(glval<null>) = FunctionAddress[MyDisposable] :
|
||||
# 14| v0_6(Void) = Call : func:r0_5, this:r0_4
|
||||
# 14| mu0_7(null) = ^CallSideEffect : ~mu0_2
|
||||
# 14| mu0_8(MyDisposable) = Store : &:r0_3, r0_4
|
||||
# 16| r0_9(glval<MyDisposable>) = VariableAddress[o1] :
|
||||
# 16| r0_10(MyDisposable) = Load : &:r0_9, ~mu0_2
|
||||
# 16| r0_11(glval<null>) = FunctionAddress[DoSomething] :
|
||||
# 16| v0_12(Void) = Call : func:r0_11, this:r0_10
|
||||
# 16| mu0_13(null) = ^CallSideEffect : ~mu0_2
|
||||
# 19| r0_14(glval<MyDisposable>) = VariableAddress[o2] :
|
||||
# 19| r0_15(MyDisposable) = NewObj :
|
||||
# 19| r0_16(glval<null>) = FunctionAddress[MyDisposable] :
|
||||
# 19| v0_17(Void) = Call : func:r0_16, this:r0_15
|
||||
# 19| mu0_18(null) = ^CallSideEffect : ~mu0_2
|
||||
# 19| mu0_19(MyDisposable) = Store : &:r0_14, r0_15
|
||||
# 22| r0_20(glval<MyDisposable>) = VariableAddress[o2] :
|
||||
# 22| r0_21(MyDisposable) = Load : &:r0_20, ~mu0_2
|
||||
# 22| r0_22(glval<null>) = FunctionAddress[DoSomething] :
|
||||
# 22| v0_23(Void) = Call : func:r0_22, this:r0_21
|
||||
# 22| mu0_24(null) = ^CallSideEffect : ~mu0_2
|
||||
# 25| r0_25(glval<MyDisposable>) = VariableAddress[o3] :
|
||||
# 25| r0_26(MyDisposable) = NewObj :
|
||||
# 25| r0_27(glval<null>) = FunctionAddress[MyDisposable] :
|
||||
# 25| v0_28(Void) = Call : func:r0_27, this:r0_26
|
||||
# 25| mu0_29(null) = ^CallSideEffect : ~mu0_2
|
||||
# 25| mu0_30(MyDisposable) = Store : &:r0_25, r0_26
|
||||
# 25| v0_31(Void) = NoOp :
|
||||
# 12| v0_32(Void) = ReturnVoid :
|
||||
# 12| v0_33(Void) = UnmodeledUse : mu*
|
||||
# 12| v0_34(Void) = ExitFunction :
|
||||
|
||||
variables.cs:
|
||||
# 5| System.Void test_variables.f()
|
||||
# 5| Block 0
|
||||
|
||||
@@ -94,5 +94,16 @@ public class test_stmts
|
||||
}
|
||||
while (x < 10);
|
||||
}
|
||||
|
||||
|
||||
public static void checkedUnchecked()
|
||||
{
|
||||
int num = Int32.MaxValue;
|
||||
unchecked
|
||||
{
|
||||
num = num + 1;
|
||||
}
|
||||
checked
|
||||
{
|
||||
num = num + 1;
|
||||
} }
|
||||
}
|
||||
|
||||
27
csharp/ql/test/library-tests/ir/ir/using.cs
Normal file
27
csharp/ql/test/library-tests/ir/ir/using.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
|
||||
class UsingStmt
|
||||
{
|
||||
public class MyDisposable : IDisposable
|
||||
{
|
||||
public MyDisposable() { }
|
||||
public void DoSomething() { }
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
static void Main()
|
||||
{
|
||||
using (var o1 = new MyDisposable())
|
||||
{
|
||||
o1.DoSomething();
|
||||
}
|
||||
|
||||
var o2 = new MyDisposable();
|
||||
using (o2)
|
||||
{
|
||||
o2.DoSomething();
|
||||
}
|
||||
|
||||
using(var o3 = new MyDisposable());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user