Skip to content

Commit b85823b

Browse files
authored
Merge pull request github#1857 from AndreiDiaconu1/ircsharp-forstmt
C# IR: More support for `ForStmt`s
2 parents 16c95d8 + 195b99c commit b85823b

File tree

9 files changed

+272
-246
lines changed

9 files changed

+272
-246
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ private module Cached {
179179
exists(TranslatedElement bodyOrUpdate |
180180
bodyOrUpdate = s.getBody()
181181
or
182-
bodyOrUpdate = s.getUpdate()
182+
bodyOrUpdate = s.getUpdate(_)
183183
|
184184
inLoop = bodyOrUpdate.getAChild*()
185185
) and

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-
* (ie. `MethodCall`) or a constructor call (ie. `ObjectCreation`). Notice that the
13+
* (eg. `MethodCall`) or a constructor call (eg. `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: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -651,43 +651,66 @@ class TranslatedForStmt extends TranslatedLoop {
651651
override ForStmt stmt;
652652

653653
override TranslatedElement getChild(int id) {
654-
id = 0 and result = this.getDeclAndInit()
654+
initializerIndex(id) and result = this.getDeclAndInit(id)
655655
or
656-
id = 1 and result = this.getCondition()
656+
result = this.getUpdate(updateIndex(id))
657657
or
658-
id = 2 and result = this.getUpdate()
658+
id = initializersNo() + updatesNo() and result = this.getCondition()
659659
or
660-
id = 3 and result = this.getBody()
660+
id = initializersNo() + updatesNo() + 1 and result = this.getBody()
661661
}
662662

663-
private TranslatedLocalDeclaration getDeclAndInit() {
664-
result = getTranslatedLocalDeclaration(stmt.getAnInitializer())
663+
private TranslatedLocalDeclaration getDeclAndInit(int index) {
664+
result = getTranslatedLocalDeclaration(stmt.getInitializer(index))
665665
}
666666

667667
private predicate hasInitialization() { exists(stmt.getAnInitializer()) }
668668

669-
TranslatedExpr getUpdate() { result = getTranslatedExpr(stmt.getAnUpdate()) }
669+
TranslatedExpr getUpdate(int index) { result = getTranslatedExpr(stmt.getUpdate(index)) }
670670

671671
private predicate hasUpdate() { exists(stmt.getAnUpdate()) }
672672

673+
private int initializersNo() { result = count(stmt.getAnInitializer()) }
674+
675+
private int updatesNo() { result = count(stmt.getAnUpdate()) }
676+
677+
private predicate initializerIndex(int index) { index in [0 .. initializersNo() - 1] }
678+
679+
private int updateIndex(int index) {
680+
result in [0 .. updatesNo() - 1] and
681+
index = initializersNo() + result
682+
}
683+
673684
override Instruction getFirstInstruction() {
674685
if this.hasInitialization()
675-
then result = this.getDeclAndInit().getFirstInstruction()
686+
then result = this.getDeclAndInit(0).getFirstInstruction()
676687
else result = this.getFirstConditionInstruction()
677688
}
678689

679690
override Instruction getChildSuccessor(TranslatedElement child) {
680-
child = this.getDeclAndInit() and
691+
exists(int index |
692+
child = this.getDeclAndInit(index) and
693+
index < initializersNo() - 1 and
694+
result = this.getDeclAndInit(index + 1).getFirstInstruction()
695+
)
696+
or
697+
child = this.getDeclAndInit(initializersNo() - 1) and
681698
result = this.getFirstConditionInstruction()
682699
or
683700
(
684701
child = this.getBody() and
685702
if this.hasUpdate()
686-
then result = this.getUpdate().getFirstInstruction()
703+
then result = this.getUpdate(0).getFirstInstruction()
687704
else result = this.getFirstConditionInstruction()
688705
)
689706
or
690-
child = this.getUpdate() and result = this.getFirstConditionInstruction()
707+
exists(int index |
708+
child = this.getUpdate(index) and
709+
result = this.getUpdate(index + 1).getFirstInstruction()
710+
)
711+
or
712+
child = this.getUpdate(updatesNo() - 1) and
713+
result = this.getFirstConditionInstruction()
691714
}
692715
}
693716

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

Lines changed: 85 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* (both AST generated and compiler generated).
44
*/
55

6-
76
import csharp
87
private import semmle.code.csharp.ir.implementation.Opcode
98
private import semmle.code.csharp.ir.implementation.internal.OperandTag
@@ -18,129 +17,112 @@ abstract class TranslatedCallBase extends TranslatedElement {
1817
override final TranslatedElement getChild(int id) {
1918
// We choose the child's id in the order of evaluation.
2019
// Note: some calls do need qualifiers, though instructions for them have already
21-
// been generated; eg. a constructor does not need to generate a qualifier,
20+
// been generated; eg. a constructor does not need to generate a qualifier,
2221
// though the `this` argument exists and is the result of the instruction
2322
// that allocated the new object. For those calls, `getQualifier()` should
2423
// be void.
25-
id = -1 and result = getQualifier() or
24+
id = -1 and result = getQualifier()
25+
or
2626
result = getArgument(id)
2727
}
2828

29-
override final Instruction getFirstInstruction() {
30-
if exists(getQualifier()) then
31-
result = getQualifier().getFirstInstruction()
32-
else
33-
result = getInstruction(CallTargetTag())
29+
final override Instruction getFirstInstruction() {
30+
if exists(getQualifier())
31+
then result = getQualifier().getFirstInstruction()
32+
else result = getInstruction(CallTargetTag())
3433
}
3534

36-
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
37-
Type resultType, boolean isLValue) {
38-
(
39-
tag = CallTag() and
40-
opcode instanceof Opcode::Call and
41-
resultType = getCallResultType() and
42-
isLValue = false
43-
) or
44-
(
45-
hasSideEffect() and
46-
tag = CallSideEffectTag() and
47-
(
48-
if hasWriteSideEffect() then (
49-
opcode instanceof Opcode::CallSideEffect and
50-
resultType instanceof Language::UnknownType
51-
)
52-
else (
53-
opcode instanceof Opcode::CallReadSideEffect and
54-
resultType instanceof Language::UnknownType
55-
)
56-
) and
57-
isLValue = false
58-
) or
35+
override predicate hasInstruction(
36+
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
37+
) {
38+
tag = CallTag() and
39+
opcode instanceof Opcode::Call and
40+
resultType = getCallResultType() and
41+
isLValue = false
42+
or
43+
hasSideEffect() and
44+
tag = CallSideEffectTag() and
5945
(
60-
tag = CallTargetTag() and
61-
opcode instanceof Opcode::FunctionAddress and
62-
// Since the DB does not have a function type,
63-
// we just use the UnknownType
64-
resultType instanceof Language::UnknownType and
65-
isLValue = true
66-
)
46+
if hasWriteSideEffect()
47+
then (
48+
opcode instanceof Opcode::CallSideEffect and
49+
resultType instanceof Language::UnknownType
50+
) else (
51+
opcode instanceof Opcode::CallReadSideEffect and
52+
resultType instanceof Language::UnknownType
53+
)
54+
) and
55+
isLValue = false
56+
or
57+
tag = CallTargetTag() and
58+
opcode instanceof Opcode::FunctionAddress and
59+
// Since the DB does not have a function type,
60+
// we just use the UnknownType
61+
resultType instanceof Language::UnknownType and
62+
isLValue = true
6763
}
64+
6865
override Instruction getChildSuccessor(TranslatedElement child) {
69-
(
70-
child = getQualifier() and
71-
result = getInstruction(CallTargetTag())
72-
) or
66+
child = getQualifier() and
67+
result = getInstruction(CallTargetTag())
68+
or
7369
exists(int argIndex |
7470
child = getArgument(argIndex) and
75-
if exists(getArgument(argIndex + 1)) then
76-
result = getArgument(argIndex + 1).getFirstInstruction()
77-
else
78-
result = getInstruction(CallTag())
71+
if exists(getArgument(argIndex + 1))
72+
then result = getArgument(argIndex + 1).getFirstInstruction()
73+
else result = getInstruction(CallTag())
7974
)
8075
}
81-
82-
override Instruction getInstructionSuccessor(InstructionTag tag,
83-
EdgeKind kind) {
76+
77+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
8478
kind instanceof GotoEdge and
8579
(
8680
(
8781
tag = CallTag() and
88-
if hasSideEffect() then
89-
result = getInstruction(CallSideEffectTag())
90-
else
91-
result = getParent().getChildSuccessor(this)
92-
) or
93-
(
94-
hasSideEffect() and
95-
tag = CallSideEffectTag() and
96-
result = getParent().getChildSuccessor(this)
97-
) or
98-
(
99-
tag = CallTargetTag() and
100-
kind instanceof GotoEdge and
101-
result = getFirstArgumentOrCallInstruction()
82+
if hasSideEffect()
83+
then result = getInstruction(CallSideEffectTag())
84+
else result = getParent().getChildSuccessor(this)
10285
)
86+
or
87+
hasSideEffect() and
88+
tag = CallSideEffectTag() and
89+
result = getParent().getChildSuccessor(this)
90+
or
91+
tag = CallTargetTag() and
92+
kind instanceof GotoEdge and
93+
result = getFirstArgumentOrCallInstruction()
10394
)
10495
}
10596

106-
override Instruction getInstructionOperand(InstructionTag tag,
107-
OperandTag operandTag) {
97+
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
98+
tag = CallTag() and
10899
(
109-
tag = CallTag() and
110-
(
111-
(
112-
operandTag instanceof CallTargetOperandTag and
113-
result = getInstruction(CallTargetTag())
114-
) or
115-
(
116-
operandTag instanceof ThisArgumentOperandTag and
117-
result = getQualifierResult()
118-
) or
119-
exists(PositionalArgumentOperandTag argTag |
120-
argTag = operandTag and
121-
result = getArgument(argTag.getArgIndex()).getResult()
122-
)
100+
operandTag instanceof CallTargetOperandTag and
101+
result = getInstruction(CallTargetTag())
102+
or
103+
operandTag instanceof ThisArgumentOperandTag and
104+
result = getQualifierResult()
105+
or
106+
exists(PositionalArgumentOperandTag argTag |
107+
argTag = operandTag and
108+
result = getArgument(argTag.getArgIndex()).getResult()
123109
)
124-
) or
125-
(
126-
tag = CallSideEffectTag() and
127-
hasSideEffect() and
128-
operandTag instanceof SideEffectOperandTag and
129-
result = getUnmodeledDefinitionInstruction()
130110
)
111+
or
112+
tag = CallSideEffectTag() and
113+
hasSideEffect() and
114+
operandTag instanceof SideEffectOperandTag and
115+
result = getUnmodeledDefinitionInstruction()
131116
}
132117

133-
override final Type getInstructionOperandType(InstructionTag tag,
134-
TypedOperandTag operandTag) {
118+
final override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
135119
tag = CallSideEffectTag() and
136120
hasSideEffect() and
137121
operandTag instanceof SideEffectOperandTag and
138122
result instanceof Language::UnknownType
139123
}
140124

141-
Instruction getResult() {
142-
result = getInstruction(CallTag())
143-
}
125+
Instruction getResult() { result = getInstruction(CallTag()) }
144126

145127
/**
146128
* Gets the result type of the call.
@@ -152,16 +134,14 @@ abstract class TranslatedCallBase extends TranslatedElement {
152134
* function (of the element this call is attached to).
153135
*/
154136
abstract Instruction getUnmodeledDefinitionInstruction();
155-
137+
156138
/**
157139
* Holds if the call has a `this` argument.
158140
*/
159-
predicate hasQualifier() {
160-
exists(getQualifier())
161-
}
141+
predicate hasQualifier() { exists(getQualifier()) }
162142

163143
/**
164-
* Gets the expr for the qualifier of the call.
144+
* Gets the expr for the qualifier of the call.
165145
*/
166146
abstract TranslatedExprBase getQualifier();
167147

@@ -186,10 +166,9 @@ abstract class TranslatedCallBase extends TranslatedElement {
186166
* argument. Otherwise, returns the call instruction.
187167
*/
188168
final Instruction getFirstArgumentOrCallInstruction() {
189-
if hasArguments() then
190-
result = getArgument(0).getFirstInstruction()
191-
else
192-
result = getInstruction(CallTag())
169+
if hasArguments()
170+
then result = getArgument(0).getFirstInstruction()
171+
else result = getInstruction(CallTag())
193172
}
194173

195174
/**
@@ -199,21 +178,15 @@ abstract class TranslatedCallBase extends TranslatedElement {
199178
exists(getArgument(0))
200179
}
201180

202-
predicate hasReadSideEffect() {
203-
any()
204-
}
181+
predicate hasReadSideEffect() { any() }
205182

206-
predicate hasWriteSideEffect() {
207-
any()
208-
}
183+
predicate hasWriteSideEffect() { any() }
209184

210-
private predicate hasSideEffect() {
211-
hasReadSideEffect() or hasWriteSideEffect()
212-
}
185+
private predicate hasSideEffect() { hasReadSideEffect() or hasWriteSideEffect() }
213186

214187
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
215-
hasSideEffect() and
216-
tag = CallSideEffectTag() and
217-
result = getResult()
188+
hasSideEffect() and
189+
tag = CallSideEffectTag() and
190+
result = getResult()
218191
}
219-
}
192+
}

0 commit comments

Comments
 (0)