Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b7db156

Browse files
authored
Merge pull request #1858 from AndreiDiaconu1/ircsharp-continue
C# IR: Add support for `ContinueStmt`
2 parents e330d5a + e55f16d commit b7db156

4 files changed

Lines changed: 281 additions & 42 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
1010

1111
/**
1212
* The IR translation of a call to a function. The function can be a normal function
13-
* (eg. `MethodCall`) or a constructor call (eg. `ObjectCreation`). Notice that the
13+
* (e.g. `MethodCall`) or a constructor call (e.g. `ObjectCreation`). Notice that the
1414
* AST generated translated calls are tied to an expression (unlike compiler generated ones,
1515
* which can be attached to either a statement or an expression).
1616
*/

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

Lines changed: 66 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -731,79 +731,104 @@ abstract class TranslatedSpecificJump extends TranslatedStmt {
731731
isLValue = false
732732
}
733733

734-
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
734+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
735+
tag = OnlyInstructionTag() and
736+
kind instanceof GotoEdge and
737+
result = getTargetInstruction()
738+
}
735739

736740
override Instruction getChildSuccessor(TranslatedElement child) { none() }
741+
742+
/**
743+
* Gets the instruction that is the target of the jump.
744+
*/
745+
abstract Instruction getTargetInstruction();
737746
}
738747

739748
class TranslatedBreakStmt extends TranslatedSpecificJump {
740749
override BreakStmt stmt;
741750

742-
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
743-
tag = OnlyInstructionTag() and
744-
kind instanceof GotoEdge and
745-
result = this.getEnclosingLoopOrSwitchNextInstr(stmt)
751+
override Instruction getTargetInstruction() {
752+
result = getEnclosingLoopOrSwitchNextInstr(stmt)
746753
}
754+
}
747755

748-
private Instruction getEnclosingLoopOrSwitchNextInstr(Stmt crtStmt) {
749-
if crtStmt instanceof LoopStmt or crtStmt instanceof SwitchStmt
750-
then
751-
result = getTranslatedStmt(crtStmt).getParent().getChildSuccessor(getTranslatedStmt(crtStmt))
752-
else result = this.getEnclosingLoopOrSwitchNextInstr(crtStmt.getParent())
756+
private Instruction getEnclosingLoopOrSwitchNextInstr(Stmt crtStmt) {
757+
if crtStmt instanceof LoopStmt or crtStmt instanceof SwitchStmt
758+
then
759+
result = getTranslatedStmt(crtStmt).getParent().getChildSuccessor(getTranslatedStmt(crtStmt))
760+
else result = getEnclosingLoopOrSwitchNextInstr(crtStmt.getParent())
761+
}
762+
763+
class TranslatedContinueStmt extends TranslatedSpecificJump {
764+
override ContinueStmt stmt;
765+
766+
override Instruction getTargetInstruction() {
767+
result = getEnclosingLoopTargetInstruction(stmt)
753768
}
754769
}
755770

771+
private Instruction getEnclosingLoopTargetInstruction(Stmt crtStmt) {
772+
if crtStmt instanceof ForStmt
773+
then result = getNextForInstruction(crtStmt)
774+
else if crtStmt instanceof LoopStmt
775+
then result = getTranslatedStmt(crtStmt).getFirstInstruction()
776+
else result = getEnclosingLoopTargetInstruction(crtStmt.getParent())
777+
}
778+
779+
private Instruction getNextForInstruction(ForStmt for) {
780+
if exists(for.getUpdate(0))
781+
then result = getTranslatedStmt(for).(TranslatedForStmt).getUpdate(0).getFirstInstruction()
782+
else if exists(for.getCondition())
783+
then result = getTranslatedStmt(for).(TranslatedForStmt).getCondition().getFirstInstruction()
784+
else result = getTranslatedStmt(for).(TranslatedForStmt).getBody().getFirstInstruction()
785+
}
786+
756787
class TranslatedGotoLabelStmt extends TranslatedSpecificJump {
757788
override GotoLabelStmt stmt;
758789

759-
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
760-
tag = OnlyInstructionTag() and
761-
kind instanceof GotoEdge and
790+
override Instruction getTargetInstruction() {
762791
result = getTranslatedStmt(stmt.getTarget()).getFirstInstruction()
763792
}
764793
}
765794

766795
class TranslatedGotoCaseStmt extends TranslatedSpecificJump {
767796
override GotoCaseStmt stmt;
768797

769-
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
770-
tag = OnlyInstructionTag() and
771-
kind instanceof GotoEdge and
772-
result = this.getCase(stmt, stmt.getExpr()).getFirstInstruction()
798+
override Instruction getTargetInstruction() {
799+
result = getCase(stmt, stmt.getExpr()).getFirstInstruction()
773800
}
801+
}
774802

775-
private TranslatedStmt getCase(Stmt crtStmt, Expr expr) {
776-
if crtStmt instanceof SwitchStmt
777-
then
778-
exists(CaseStmt caseStmt |
779-
caseStmt = crtStmt.(SwitchStmt).getACase() and
780-
// We check for the constant value of the expression
781-
// since we can't check for equality between `PatternExpr` and `Expr`
782-
caseStmt.getPattern().getValue() = expr.getValue() and
783-
result = getTranslatedStmt(caseStmt)
784-
)
785-
else result = this.getCase(crtStmt.getParent(), expr)
786-
}
803+
private TranslatedStmt getCase(Stmt crtStmt, Expr expr) {
804+
if crtStmt instanceof SwitchStmt
805+
then
806+
exists(CaseStmt caseStmt |
807+
caseStmt = crtStmt.(SwitchStmt).getACase() and
808+
// We check for the constant value of the expression
809+
// since we can't check for equality between `PatternExpr` and `Expr`
810+
caseStmt.getPattern().getValue() = expr.getValue() and
811+
result = getTranslatedStmt(caseStmt)
812+
)
813+
else result = getCase(crtStmt.getParent(), expr)
787814
}
788815

789816
class TranslatedGotoDefaultStmt extends TranslatedSpecificJump {
790817
override GotoDefaultStmt stmt;
791818

792-
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
793-
tag = OnlyInstructionTag() and
794-
kind instanceof GotoEdge and
819+
override Instruction getTargetInstruction() {
795820
result = getDefaultCase(stmt).getFirstInstruction()
796821
}
822+
}
797823

798-
private TranslatedStmt getDefaultCase(Stmt crtStmt) {
799-
if crtStmt instanceof SwitchStmt
800-
then
801-
exists(CaseStmt caseStmt |
802-
caseStmt = crtStmt.(SwitchStmt).getDefaultCase() and
803-
result = getTranslatedStmt(caseStmt)
804-
)
805-
else result = this.getDefaultCase(crtStmt.getParent())
806-
}
824+
private TranslatedStmt getDefaultCase(Stmt crtStmt) {
825+
if crtStmt instanceof SwitchStmt
826+
then
827+
exists(CaseStmt caseStmt |
828+
caseStmt = crtStmt.(SwitchStmt).getDefaultCase() and
829+
result = getTranslatedStmt(caseStmt)
830+
)
831+
else result = getDefaultCase(crtStmt.getParent())
807832
}
808833

809834
class TranslatedSwitchStmt extends TranslatedStmt {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
3+
class Jumps
4+
{
5+
public static void Main()
6+
{
7+
for (int i = 1; i <= 10; i++)
8+
{
9+
if (i == 3)
10+
continue;
11+
else if (i == 5)
12+
break;
13+
Console.WriteLine("BreakAndContinue");
14+
}
15+
16+
for (int i = 0 ; i < 10 ; )
17+
{
18+
i++;
19+
continue;
20+
}
21+
22+
int a = 0;
23+
while (true)
24+
{
25+
a++;
26+
if (a == 5)
27+
continue;
28+
if (a == 10)
29+
break;
30+
}
31+
32+
for (int i = 1; i <= 10; i++)
33+
{
34+
if (i == 5)
35+
goto done;
36+
}
37+
done:
38+
Console.WriteLine("Done");
39+
}
40+
}

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

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,180 @@ isexpr.cs:
603603
# 18| v6_0(Void) = NoOp :
604604
#-----| Goto -> Block 1
605605

606+
jumps.cs:
607+
# 5| System.Void Jumps.Main()
608+
# 5| Block 0
609+
# 5| v0_0(Void) = EnterFunction :
610+
# 5| mu0_1(null) = AliasedDefinition :
611+
# 5| mu0_2(null) = UnmodeledDefinition :
612+
# 7| r0_3(glval<Int32>) = VariableAddress[i] :
613+
# 7| r0_4(Int32) = Constant[1] :
614+
# 7| mu0_5(Int32) = Store : &:r0_3, r0_4
615+
#-----| Goto -> Block 1
616+
617+
# 7| Block 1
618+
# 7| r1_0(glval<Int32>) = VariableAddress[i] :
619+
# 7| r1_1(Int32) = Load : &:r1_0, ~mu0_2
620+
# 7| r1_2(Int32) = Constant[10] :
621+
# 7| r1_3(Boolean) = CompareLE : r1_1, r1_2
622+
# 7| v1_4(Void) = ConditionalBranch : r1_3
623+
#-----| False -> Block 7
624+
#-----| True -> Block 2
625+
626+
# 9| Block 2
627+
# 9| r2_0(glval<Int32>) = VariableAddress[i] :
628+
# 9| r2_1(Int32) = Load : &:r2_0, ~mu0_2
629+
# 9| r2_2(Int32) = Constant[3] :
630+
# 9| r2_3(Boolean) = CompareEQ : r2_1, r2_2
631+
# 9| v2_4(Void) = ConditionalBranch : r2_3
632+
#-----| False -> Block 4
633+
#-----| True -> Block 3
634+
635+
# 10| Block 3
636+
# 10| v3_0(Void) = NoOp :
637+
#-----| Goto -> Block 19
638+
639+
# 11| Block 4
640+
# 11| r4_0(glval<Int32>) = VariableAddress[i] :
641+
# 11| r4_1(Int32) = Load : &:r4_0, ~mu0_2
642+
# 11| r4_2(Int32) = Constant[5] :
643+
# 11| r4_3(Boolean) = CompareEQ : r4_1, r4_2
644+
# 11| v4_4(Void) = ConditionalBranch : r4_3
645+
#-----| False -> Block 6
646+
#-----| True -> Block 5
647+
648+
# 12| Block 5
649+
# 12| v5_0(Void) = NoOp :
650+
#-----| Goto -> Block 7
651+
652+
# 13| Block 6
653+
# 13| r6_0(glval<null>) = FunctionAddress[WriteLine] :
654+
# 13| r6_1(String) = StringConstant["BreakAndContinue"] :
655+
# 13| v6_2(Void) = Call : func:r6_0, 0:r6_1
656+
# 13| mu6_3(null) = ^CallSideEffect : ~mu0_2
657+
#-----| Goto -> Block 19
658+
659+
# 16| Block 7
660+
# 16| r7_0(glval<Int32>) = VariableAddress[i] :
661+
# 16| r7_1(Int32) = Constant[0] :
662+
# 16| mu7_2(Int32) = Store : &:r7_0, r7_1
663+
#-----| Goto -> Block 8
664+
665+
# 16| Block 8
666+
# 16| r8_0(glval<Int32>) = VariableAddress[i] :
667+
# 16| r8_1(Int32) = Load : &:r8_0, ~mu0_2
668+
# 16| r8_2(Int32) = Constant[10] :
669+
# 16| r8_3(Boolean) = CompareLT : r8_1, r8_2
670+
# 16| v8_4(Void) = ConditionalBranch : r8_3
671+
#-----| False -> Block 10
672+
#-----| True -> Block 9
673+
674+
# 18| Block 9
675+
# 18| r9_0(glval<Int32>) = VariableAddress[i] :
676+
# 18| r9_1(Int32) = Load : &:r9_0, ~mu0_2
677+
# 18| r9_2(Int32) = Constant[1] :
678+
# 18| r9_3(Int32) = Add : r9_1, r9_2
679+
# 18| mu9_4(Int32) = Store : &:r9_0, r9_3
680+
# 19| v9_5(Void) = NoOp :
681+
#-----| Goto (back edge) -> Block 8
682+
683+
# 22| Block 10
684+
# 22| r10_0(glval<Int32>) = VariableAddress[a] :
685+
# 22| r10_1(Int32) = Constant[0] :
686+
# 22| mu10_2(Int32) = Store : &:r10_0, r10_1
687+
#-----| Goto -> Block 11
688+
689+
# 23| Block 11
690+
# 23| r11_0(Boolean) = Constant[true] :
691+
# 23| v11_1(Void) = ConditionalBranch : r11_0
692+
#-----| False -> Block 16
693+
#-----| True -> Block 12
694+
695+
# 25| Block 12
696+
# 25| r12_0(glval<Int32>) = VariableAddress[a] :
697+
# 25| r12_1(Int32) = Load : &:r12_0, ~mu0_2
698+
# 25| r12_2(Int32) = Constant[1] :
699+
# 25| r12_3(Int32) = Add : r12_1, r12_2
700+
# 25| mu12_4(Int32) = Store : &:r12_0, r12_3
701+
# 26| r12_5(glval<Int32>) = VariableAddress[a] :
702+
# 26| r12_6(Int32) = Load : &:r12_5, ~mu0_2
703+
# 26| r12_7(Int32) = Constant[5] :
704+
# 26| r12_8(Boolean) = CompareEQ : r12_6, r12_7
705+
# 26| v12_9(Void) = ConditionalBranch : r12_8
706+
#-----| False -> Block 14
707+
#-----| True -> Block 13
708+
709+
# 27| Block 13
710+
# 27| v13_0(Void) = NoOp :
711+
#-----| Goto (back edge) -> Block 11
712+
713+
# 28| Block 14
714+
# 28| r14_0(glval<Int32>) = VariableAddress[a] :
715+
# 28| r14_1(Int32) = Load : &:r14_0, ~mu0_2
716+
# 28| r14_2(Int32) = Constant[10] :
717+
# 28| r14_3(Boolean) = CompareEQ : r14_1, r14_2
718+
# 28| v14_4(Void) = ConditionalBranch : r14_3
719+
#-----| False (back edge) -> Block 11
720+
#-----| True -> Block 15
721+
722+
# 29| Block 15
723+
# 29| v15_0(Void) = NoOp :
724+
#-----| Goto -> Block 16
725+
726+
# 32| Block 16
727+
# 32| r16_0(glval<Int32>) = VariableAddress[i] :
728+
# 32| r16_1(Int32) = Constant[1] :
729+
# 32| mu16_2(Int32) = Store : &:r16_0, r16_1
730+
#-----| Goto -> Block 18
731+
732+
# 32| Block 17
733+
# 32| r17_0(glval<Int32>) = VariableAddress[i] :
734+
# 32| r17_1(Int32) = Load : &:r17_0, ~mu0_2
735+
# 32| r17_2(Int32) = Constant[1] :
736+
# 32| r17_3(Int32) = Add : r17_1, r17_2
737+
# 32| mu17_4(Int32) = Store : &:r17_0, r17_3
738+
#-----| Goto (back edge) -> Block 18
739+
740+
# 32| Block 18
741+
# 32| r18_0(glval<Int32>) = VariableAddress[i] :
742+
# 32| r18_1(Int32) = Load : &:r18_0, ~mu0_2
743+
# 32| r18_2(Int32) = Constant[10] :
744+
# 32| r18_3(Boolean) = CompareLE : r18_1, r18_2
745+
# 32| v18_4(Void) = ConditionalBranch : r18_3
746+
#-----| False -> Block 22
747+
#-----| True -> Block 20
748+
749+
# 7| Block 19
750+
# 7| r19_0(glval<Int32>) = VariableAddress[i] :
751+
# 7| r19_1(Int32) = Load : &:r19_0, ~mu0_2
752+
# 7| r19_2(Int32) = Constant[1] :
753+
# 7| r19_3(Int32) = Add : r19_1, r19_2
754+
# 7| mu19_4(Int32) = Store : &:r19_0, r19_3
755+
#-----| Goto (back edge) -> Block 1
756+
757+
# 34| Block 20
758+
# 34| r20_0(glval<Int32>) = VariableAddress[i] :
759+
# 34| r20_1(Int32) = Load : &:r20_0, ~mu0_2
760+
# 34| r20_2(Int32) = Constant[5] :
761+
# 34| r20_3(Boolean) = CompareEQ : r20_1, r20_2
762+
# 34| v20_4(Void) = ConditionalBranch : r20_3
763+
#-----| False -> Block 17
764+
#-----| True -> Block 21
765+
766+
# 35| Block 21
767+
# 35| v21_0(Void) = NoOp :
768+
#-----| Goto -> Block 22
769+
770+
# 37| Block 22
771+
# 37| v22_0(Void) = NoOp :
772+
# 38| r22_1(glval<null>) = FunctionAddress[WriteLine] :
773+
# 38| r22_2(String) = StringConstant["Done"] :
774+
# 38| v22_3(Void) = Call : func:r22_1, 0:r22_2
775+
# 38| mu22_4(null) = ^CallSideEffect : ~mu0_2
776+
# 5| v22_5(Void) = ReturnVoid :
777+
# 5| v22_6(Void) = UnmodeledUse : mu*
778+
# 5| v22_7(Void) = ExitFunction :
779+
606780
lock.cs:
607781
# 5| System.Void LockTest.A()
608782
# 5| Block 0

0 commit comments

Comments
 (0)