Skip to content

Commit 5e0addc

Browse files
author
AndreiDiaconu1
committed
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.
1 parent 396a72d commit 5e0addc

File tree

5 files changed

+252
-1
lines changed

5 files changed

+252
-1
lines changed

csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ private predicate ignoreExprOnly(Expr expr) {
8989
or
9090
// Ignore the child expression of a goto case stmt
9191
expr.getParent() instanceof GotoCaseStmt
92+
or
93+
// Ignore the expression (that is not a declaration)
94+
// that appears in a using block
95+
expr.getParent().(UsingBlockStmt).getExpr() = expr
9296
}
9397

9498
/**
@@ -178,6 +182,7 @@ newtype TTranslatedElement =
178182
// expression.
179183
TTranslatedLoad(Expr expr) {
180184
// TODO: Revisit and make sure Loads are only used when needed
185+
not ignoreExpr(expr) and
181186
expr instanceof AssignableRead and
182187
not expr.getParent() instanceof ArrayAccess and
183188
not (

csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,3 +966,114 @@ class TranslatedLockStmt extends TranslatedStmt {
966966
result = LockElements::getLockWasTakenDecl(stmt)
967967
}
968968
}
969+
970+
// TODO: Should be modeled using the desugaring framework for a
971+
// more exact translation.
972+
class TranslatedCheckedUncheckedStmt extends TranslatedStmt {
973+
TranslatedCheckedUncheckedStmt() {
974+
stmt instanceof CheckedStmt or
975+
stmt instanceof UncheckedStmt
976+
}
977+
978+
override TranslatedElement getChild(int id) { id = 0 and result = this.getBody() }
979+
980+
override Instruction getFirstInstruction() { result = this.getBody().getFirstInstruction() }
981+
982+
override Instruction getChildSuccessor(TranslatedElement child) {
983+
child = this.getBody() and
984+
result = this.getParent().getChildSuccessor(this)
985+
}
986+
987+
override predicate hasInstruction(
988+
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
989+
) {
990+
none()
991+
}
992+
993+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
994+
995+
private TranslatedElement getBody() {
996+
result = getTranslatedStmt(stmt.(CheckedStmt).getBlock()) or
997+
result = getTranslatedStmt(stmt.(UncheckedStmt).getBlock())
998+
}
999+
}
1000+
1001+
// TODO: Should be modeled using the desugaring framework for a
1002+
// more exact translation.
1003+
class TranslatedUsingBlockStmt extends TranslatedStmt {
1004+
override UsingBlockStmt stmt;
1005+
1006+
override TranslatedElement getChild(int id) {
1007+
result = getDecl(id)
1008+
or
1009+
id = noDecls() and result = this.getBody()
1010+
}
1011+
1012+
override Instruction getFirstInstruction() {
1013+
if noDecls() > 0
1014+
then result = this.getDecl(0).getFirstInstruction()
1015+
else result = this.getBody().getFirstInstruction()
1016+
}
1017+
1018+
override Instruction getChildSuccessor(TranslatedElement child) {
1019+
exists(int id |
1020+
child = this.getDecl(id) and
1021+
id < this.noDecls() - 1 and
1022+
result = this.getDecl(id + 1).getFirstInstruction()
1023+
)
1024+
or
1025+
child = this.getDecl(this.noDecls() - 1) and result = this.getBody().getFirstInstruction()
1026+
or
1027+
child = this.getBody() and result = this.getParent().getChildSuccessor(this)
1028+
}
1029+
1030+
override predicate hasInstruction(
1031+
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
1032+
) {
1033+
none()
1034+
}
1035+
1036+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
1037+
1038+
private TranslatedLocalDeclaration getDecl(int id) {
1039+
result = getTranslatedLocalDeclaration(stmt.getVariableDeclExpr(id))
1040+
}
1041+
1042+
private int noDecls() { result = count(stmt.getAVariableDeclExpr()) }
1043+
1044+
private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getBody()) }
1045+
}
1046+
1047+
// TODO: Should be modeled using the desugaring framework for a
1048+
// more exact translation.
1049+
class TranslatedUsingDeclStmt extends TranslatedStmt {
1050+
override UsingDeclStmt stmt;
1051+
1052+
override TranslatedElement getChild(int id) { result = getDecl(id) }
1053+
1054+
override Instruction getFirstInstruction() { result = this.getDecl(0).getFirstInstruction() }
1055+
1056+
override Instruction getChildSuccessor(TranslatedElement child) {
1057+
exists(int id |
1058+
child = this.getDecl(id) and
1059+
id < this.noDecls() - 1 and
1060+
result = this.getDecl(id + 1).getFirstInstruction()
1061+
)
1062+
or
1063+
child = this.getDecl(this.noDecls() - 1) and result = this.getParent().getChildSuccessor(this)
1064+
}
1065+
1066+
override predicate hasInstruction(
1067+
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
1068+
) {
1069+
none()
1070+
}
1071+
1072+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
1073+
1074+
private TranslatedLocalDeclaration getDecl(int id) {
1075+
result = getTranslatedLocalDeclaration(stmt.getVariableDeclExpr(id))
1076+
}
1077+
1078+
private int noDecls() { result = count(stmt.getAVariableDeclExpr()) }
1079+
}

csharp/ql/test/library-tests/ir/ir/raw_ir.expected

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,103 @@ stmts.cs:
13901390
#-----| False -> Block 1
13911391
#-----| True (back edge) -> Block 2
13921392

1393+
# 87| System.Void test_stmts.checkedUnchecked()
1394+
# 87| Block 0
1395+
# 87| v0_0(Void) = EnterFunction :
1396+
# 87| mu0_1(null) = AliasedDefinition :
1397+
# 87| mu0_2(null) = UnmodeledDefinition :
1398+
# 89| r0_3(glval<Int32>) = VariableAddress[num] :
1399+
# 89| r0_4(Int32) = Constant[2147483647] :
1400+
# 89| r0_5(Int32) = Load : &:r0_4, ~mu0_2
1401+
# 89| mu0_6(Int32) = Store : &:r0_3, r0_5
1402+
# 92| r0_7(glval<Int32>) = VariableAddress[num] :
1403+
# 92| r0_8(Int32) = Load : &:r0_7, ~mu0_2
1404+
# 92| r0_9(Int32) = Constant[1] :
1405+
# 92| r0_10(Int32) = Add : r0_8, r0_9
1406+
# 92| r0_11(glval<Int32>) = VariableAddress[num] :
1407+
# 92| mu0_12(Int32) = Store : &:r0_11, r0_10
1408+
# 96| r0_13(glval<Int32>) = VariableAddress[num] :
1409+
# 96| r0_14(Int32) = Load : &:r0_13, ~mu0_2
1410+
# 96| r0_15(Int32) = Constant[1] :
1411+
# 96| r0_16(Int32) = Add : r0_14, r0_15
1412+
# 96| r0_17(glval<Int32>) = VariableAddress[num] :
1413+
# 96| mu0_18(Int32) = Store : &:r0_17, r0_16
1414+
# 87| v0_19(Void) = ReturnVoid :
1415+
# 87| v0_20(Void) = UnmodeledUse : mu*
1416+
# 87| v0_21(Void) = ExitFunction :
1417+
1418+
using.cs:
1419+
# 7| System.Void UsingStmt.MyDisposable..ctor()
1420+
# 7| Block 0
1421+
# 7| v0_0(Void) = EnterFunction :
1422+
# 7| mu0_1(null) = AliasedDefinition :
1423+
# 7| mu0_2(null) = UnmodeledDefinition :
1424+
# 7| r0_3(glval<MyDisposable>) = InitializeThis :
1425+
# 7| v0_4(Void) = NoOp :
1426+
# 7| v0_5(Void) = ReturnVoid :
1427+
# 7| v0_6(Void) = UnmodeledUse : mu*
1428+
# 7| v0_7(Void) = ExitFunction :
1429+
1430+
# 8| System.Void UsingStmt.MyDisposable.DoSomething()
1431+
# 8| Block 0
1432+
# 8| v0_0(Void) = EnterFunction :
1433+
# 8| mu0_1(null) = AliasedDefinition :
1434+
# 8| mu0_2(null) = UnmodeledDefinition :
1435+
# 8| r0_3(glval<MyDisposable>) = InitializeThis :
1436+
# 8| v0_4(Void) = NoOp :
1437+
# 8| v0_5(Void) = ReturnVoid :
1438+
# 8| v0_6(Void) = UnmodeledUse : mu*
1439+
# 8| v0_7(Void) = ExitFunction :
1440+
1441+
# 9| System.Void UsingStmt.MyDisposable.Dispose()
1442+
# 9| Block 0
1443+
# 9| v0_0(Void) = EnterFunction :
1444+
# 9| mu0_1(null) = AliasedDefinition :
1445+
# 9| mu0_2(null) = UnmodeledDefinition :
1446+
# 9| r0_3(glval<MyDisposable>) = InitializeThis :
1447+
# 9| v0_4(Void) = NoOp :
1448+
# 9| v0_5(Void) = ReturnVoid :
1449+
# 9| v0_6(Void) = UnmodeledUse : mu*
1450+
# 9| v0_7(Void) = ExitFunction :
1451+
1452+
# 12| System.Void UsingStmt.Main()
1453+
# 12| Block 0
1454+
# 12| v0_0(Void) = EnterFunction :
1455+
# 12| mu0_1(null) = AliasedDefinition :
1456+
# 12| mu0_2(null) = UnmodeledDefinition :
1457+
# 14| r0_3(glval<MyDisposable>) = VariableAddress[o1] :
1458+
# 14| r0_4(MyDisposable) = NewObj :
1459+
# 14| r0_5(glval<null>) = FunctionAddress[MyDisposable] :
1460+
# 14| v0_6(Void) = Call : func:r0_5, this:r0_4
1461+
# 14| mu0_7(null) = ^CallSideEffect : ~mu0_2
1462+
# 14| mu0_8(MyDisposable) = Store : &:r0_3, r0_4
1463+
# 16| r0_9(glval<MyDisposable>) = VariableAddress[o1] :
1464+
# 16| r0_10(MyDisposable) = Load : &:r0_9, ~mu0_2
1465+
# 16| r0_11(glval<null>) = FunctionAddress[DoSomething] :
1466+
# 16| v0_12(Void) = Call : func:r0_11, this:r0_10
1467+
# 16| mu0_13(null) = ^CallSideEffect : ~mu0_2
1468+
# 19| r0_14(glval<MyDisposable>) = VariableAddress[o2] :
1469+
# 19| r0_15(MyDisposable) = NewObj :
1470+
# 19| r0_16(glval<null>) = FunctionAddress[MyDisposable] :
1471+
# 19| v0_17(Void) = Call : func:r0_16, this:r0_15
1472+
# 19| mu0_18(null) = ^CallSideEffect : ~mu0_2
1473+
# 19| mu0_19(MyDisposable) = Store : &:r0_14, r0_15
1474+
# 22| r0_20(glval<MyDisposable>) = VariableAddress[o2] :
1475+
# 22| r0_21(MyDisposable) = Load : &:r0_20, ~mu0_2
1476+
# 22| r0_22(glval<null>) = FunctionAddress[DoSomething] :
1477+
# 22| v0_23(Void) = Call : func:r0_22, this:r0_21
1478+
# 22| mu0_24(null) = ^CallSideEffect : ~mu0_2
1479+
# 25| r0_25(glval<MyDisposable>) = VariableAddress[o3] :
1480+
# 25| r0_26(MyDisposable) = NewObj :
1481+
# 25| r0_27(glval<null>) = FunctionAddress[MyDisposable] :
1482+
# 25| v0_28(Void) = Call : func:r0_27, this:r0_26
1483+
# 25| mu0_29(null) = ^CallSideEffect : ~mu0_2
1484+
# 25| mu0_30(MyDisposable) = Store : &:r0_25, r0_26
1485+
# 25| v0_31(Void) = NoOp :
1486+
# 12| v0_32(Void) = ReturnVoid :
1487+
# 12| v0_33(Void) = UnmodeledUse : mu*
1488+
# 12| v0_34(Void) = ExitFunction :
1489+
13931490
variables.cs:
13941491
# 5| System.Void test_variables.f()
13951492
# 5| Block 0

csharp/ql/test/library-tests/ir/ir/stmts.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,16 @@ public static void doWhile()
9494
}
9595
while (x < 10);
9696
}
97-
97+
98+
public static void checkedUnchecked()
99+
{
100+
int num = Int32.MaxValue;
101+
unchecked
102+
{
103+
num = num + 1;
104+
}
105+
checked
106+
{
107+
num = num + 1;
108+
} }
98109
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
3+
class UsingStmt
4+
{
5+
public class MyDisposable : IDisposable
6+
{
7+
public MyDisposable() { }
8+
public void DoSomething() { }
9+
public void Dispose() { }
10+
}
11+
12+
static void Main()
13+
{
14+
using (var o1 = new MyDisposable())
15+
{
16+
o1.DoSomething();
17+
}
18+
19+
var o2 = new MyDisposable();
20+
using (o2)
21+
{
22+
o2.DoSomething();
23+
}
24+
25+
using(var o3 = new MyDisposable());
26+
}
27+
}

0 commit comments

Comments
 (0)