Skip to content

Commit 98c30b8

Browse files
authored
Merge pull request github#11761 from MathiasVP/ir-for-microsoft-try-except-finally
C++: Generate IR for `__try __finally` and `__try __except`
2 parents 7201071 + a974cb1 commit 98c30b8

13 files changed

+1334
-34
lines changed

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,19 @@ newtype TInstructionTag =
7272
AsmInputTag(int elementIndex) { exists(AsmStmt asm | exists(asm.getChild(elementIndex))) } or
7373
ThisAddressTag() or
7474
ThisLoadTag() or
75-
StructuredBindingAccessTag()
75+
StructuredBindingAccessTag() or
76+
// The next three cases handle generation of the constants -1, 0 and 1 for __except handling.
77+
TryExceptGenerateNegativeOne() or
78+
TryExceptGenerateZero() or
79+
TryExceptGenerateOne() or
80+
// The next three cases handle generation of comparisons for __except handling.
81+
TryExceptCompareNegativeOne() or
82+
TryExceptCompareZero() or
83+
TryExceptCompareOne() or
84+
// The next three cases handle generation of branching for __except handling.
85+
TryExceptCompareNegativeOneBranch() or
86+
TryExceptCompareZeroBranch() or
87+
TryExceptCompareOneBranch()
7688

7789
class InstructionTag extends TInstructionTag {
7890
final string toString() { result = "Tag" }
@@ -224,4 +236,22 @@ string getInstructionTagId(TInstructionTag tag) {
224236
tag = ThisLoadTag() and result = "ThisLoad"
225237
or
226238
tag = StructuredBindingAccessTag() and result = "StructuredBindingAccess"
239+
or
240+
tag = TryExceptCompareNegativeOne() and result = "TryExceptCompareNegativeOne"
241+
or
242+
tag = TryExceptCompareZero() and result = "TryExceptCompareZero"
243+
or
244+
tag = TryExceptCompareOne() and result = "TryExceptCompareOne"
245+
or
246+
tag = TryExceptGenerateNegativeOne() and result = "TryExceptGenerateNegativeOne"
247+
or
248+
tag = TryExceptGenerateZero() and result = "TryExceptGenerateNegativeOne"
249+
or
250+
tag = TryExceptGenerateOne() and result = "TryExceptGenerateOne"
251+
or
252+
tag = TryExceptCompareNegativeOneBranch() and result = "TryExceptCompareNegativeOneBranch"
253+
or
254+
tag = TryExceptCompareZeroBranch() and result = "TryExceptCompareZeroBranch"
255+
or
256+
tag = TryExceptCompareOneBranch() and result = "TryExceptCompareOneBranch"
227257
}

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,7 @@ newtype TTranslatedElement =
675675
} or
676676
// A statement
677677
TTranslatedStmt(Stmt stmt) { translateStmt(stmt) } or
678+
TTranslatedMicrosoftTryExceptHandler(MicrosoftTryExceptStmt stmt) or
678679
// A function
679680
TTranslatedFunction(Function func) { translateFunction(func) } or
680681
// A constructor init list

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll

Lines changed: 277 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,222 @@ private import TranslatedInitialization
1313

1414
TranslatedStmt getTranslatedStmt(Stmt stmt) { result.getAst() = stmt }
1515

16+
TranslatedMicrosoftTryExceptHandler getTranslatedMicrosoftTryExceptHandler(
17+
MicrosoftTryExceptStmt tryExcept
18+
) {
19+
result.getAst() = tryExcept.getExcept()
20+
}
21+
22+
class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
23+
TTranslatedMicrosoftTryExceptHandler {
24+
MicrosoftTryExceptStmt tryExcept;
25+
26+
TranslatedMicrosoftTryExceptHandler() { this = TTranslatedMicrosoftTryExceptHandler(tryExcept) }
27+
28+
final override string toString() { result = tryExcept.toString() }
29+
30+
final override Locatable getAst() { result = tryExcept.getExcept() }
31+
32+
override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() }
33+
34+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
35+
// t1 = -1
36+
tag = TryExceptGenerateNegativeOne() and
37+
opcode instanceof Opcode::Constant and
38+
resultType = getIntType()
39+
or
40+
// t2 = cmp t1, condition
41+
tag = TryExceptCompareNegativeOne() and
42+
opcode instanceof Opcode::CompareEQ and
43+
resultType = getBoolType()
44+
or
45+
// if t2 goto ... else goto ...
46+
tag = TryExceptCompareNegativeOneBranch() and
47+
opcode instanceof Opcode::ConditionalBranch and
48+
resultType = getVoidType()
49+
or
50+
// t1 = 0
51+
tag = TryExceptGenerateZero() and
52+
opcode instanceof Opcode::Constant and
53+
resultType = getIntType()
54+
or
55+
// t2 = cmp t1, condition
56+
tag = TryExceptCompareZero() and
57+
opcode instanceof Opcode::CompareEQ and
58+
resultType = getBoolType()
59+
or
60+
// if t2 goto ... else goto ...
61+
tag = TryExceptCompareZeroBranch() and
62+
opcode instanceof Opcode::ConditionalBranch and
63+
resultType = getVoidType()
64+
or
65+
// t1 = 1
66+
tag = TryExceptGenerateOne() and
67+
opcode instanceof Opcode::Constant and
68+
resultType = getIntType()
69+
or
70+
// t2 = cmp t1, condition
71+
tag = TryExceptCompareOne() and
72+
opcode instanceof Opcode::CompareEQ and
73+
resultType = getBoolType()
74+
or
75+
// if t2 goto ... else goto ...
76+
tag = TryExceptCompareOneBranch() and
77+
opcode instanceof Opcode::ConditionalBranch and
78+
resultType = getVoidType()
79+
or
80+
// unwind stack
81+
tag = UnwindTag() and
82+
opcode instanceof Opcode::Unwind and
83+
resultType = getVoidType()
84+
}
85+
86+
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
87+
tag = TryExceptCompareNegativeOne() and
88+
(
89+
operandTag instanceof LeftOperandTag and
90+
result = this.getTranslatedCondition().getResult()
91+
or
92+
operandTag instanceof RightOperandTag and
93+
result = this.getInstruction(TryExceptGenerateNegativeOne())
94+
)
95+
or
96+
tag = TryExceptCompareNegativeOneBranch() and
97+
operandTag instanceof ConditionOperandTag and
98+
result = this.getInstruction(TryExceptCompareNegativeOne())
99+
or
100+
tag = TryExceptCompareZero() and
101+
(
102+
operandTag instanceof LeftOperandTag and
103+
result = this.getTranslatedCondition().getResult()
104+
or
105+
operandTag instanceof RightOperandTag and
106+
result = this.getInstruction(TryExceptGenerateZero())
107+
)
108+
or
109+
tag = TryExceptCompareZeroBranch() and
110+
operandTag instanceof ConditionOperandTag and
111+
result = this.getInstruction(TryExceptCompareZero())
112+
or
113+
tag = TryExceptCompareOne() and
114+
(
115+
operandTag instanceof LeftOperandTag and
116+
result = this.getTranslatedCondition().getResult()
117+
or
118+
operandTag instanceof RightOperandTag and
119+
result = this.getInstruction(TryExceptGenerateOne())
120+
)
121+
or
122+
tag = TryExceptCompareOneBranch() and
123+
operandTag instanceof ConditionOperandTag and
124+
result = this.getInstruction(TryExceptCompareOne())
125+
}
126+
127+
override string getInstructionConstantValue(InstructionTag tag) {
128+
tag = TryExceptGenerateNegativeOne() and
129+
result = "-1"
130+
or
131+
tag = TryExceptGenerateZero() and
132+
result = "0"
133+
or
134+
tag = TryExceptGenerateOne() and
135+
result = "1"
136+
}
137+
138+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
139+
// Generate -1 -> Compare condition
140+
tag = TryExceptGenerateNegativeOne() and
141+
kind instanceof GotoEdge and
142+
result = this.getInstruction(TryExceptCompareNegativeOne())
143+
or
144+
// Compare condition -> Branch
145+
tag = TryExceptCompareNegativeOne() and
146+
kind instanceof GotoEdge and
147+
result = this.getInstruction(TryExceptCompareNegativeOneBranch())
148+
or
149+
// Branch -> Unwind or Generate 0
150+
tag = TryExceptCompareNegativeOneBranch() and
151+
(
152+
kind instanceof TrueEdge and
153+
// TODO: This is not really correct. The semantics of `EXCEPTION_CONTINUE_EXECUTION` is that
154+
// we should continue execution at the point where the exception occurred. But we don't have
155+
// any instruction to model this behavior.
156+
result = this.getInstruction(UnwindTag())
157+
or
158+
kind instanceof FalseEdge and
159+
result = this.getInstruction(TryExceptGenerateZero())
160+
)
161+
or
162+
// Generate 0 -> Compare condition
163+
tag = TryExceptGenerateZero() and
164+
kind instanceof GotoEdge and
165+
result = this.getInstruction(TryExceptCompareZero())
166+
or
167+
// Compare condition -> Branch
168+
tag = TryExceptCompareZero() and
169+
kind instanceof GotoEdge and
170+
result = this.getInstruction(TryExceptCompareZeroBranch())
171+
or
172+
// Branch -> Unwind or Generate 1
173+
tag = TryExceptCompareZeroBranch() and
174+
(
175+
kind instanceof TrueEdge and
176+
result = this.getInstruction(UnwindTag())
177+
or
178+
kind instanceof FalseEdge and
179+
result = this.getInstruction(TryExceptGenerateOne())
180+
)
181+
or
182+
// Generate 1 -> Compare condition
183+
tag = TryExceptGenerateOne() and
184+
kind instanceof GotoEdge and
185+
result = this.getInstruction(TryExceptCompareOne())
186+
or
187+
// Compare condition -> Branch
188+
tag = TryExceptCompareOne() and
189+
kind instanceof GotoEdge and
190+
result = this.getInstruction(TryExceptCompareOneBranch())
191+
or
192+
// Branch -> Handler (the condition value is always 0, -1 or 1, and we've checked for 0 or -1 already.)
193+
tag = TryExceptCompareOneBranch() and
194+
(
195+
kind instanceof TrueEdge and
196+
result = this.getTranslatedHandler().getFirstInstruction()
197+
)
198+
or
199+
// Unwind -> Parent
200+
tag = UnwindTag() and
201+
kind instanceof GotoEdge and
202+
result = this.getParent().getChildSuccessor(this)
203+
}
204+
205+
override Instruction getChildSuccessor(TranslatedElement child) {
206+
child = this.getTranslatedCondition() and
207+
result = this.getInstruction(TryExceptGenerateNegativeOne())
208+
or
209+
child = this.getTranslatedHandler() and
210+
result = this.getParent().getChildSuccessor(this)
211+
}
212+
213+
private TranslatedExpr getTranslatedCondition() {
214+
result = getTranslatedExpr(tryExcept.getCondition())
215+
}
216+
217+
private TranslatedStmt getTranslatedHandler() {
218+
result = getTranslatedStmt(tryExcept.getExcept())
219+
}
220+
221+
override TranslatedElement getChild(int id) {
222+
id = 0 and
223+
result = this.getTranslatedCondition()
224+
or
225+
id = 1 and
226+
result = this.getTranslatedHandler()
227+
}
228+
229+
final override Function getFunction() { result = tryExcept.getEnclosingFunction() }
230+
}
231+
16232
abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
17233
Stmt stmt;
18234

@@ -249,15 +465,57 @@ class TranslatedUnreachableReturnStmt extends TranslatedReturnStmt {
249465
}
250466

251467
/**
252-
* The IR translation of a C++ `try` statement.
468+
* A C/C++ `try` statement, or a `__try __except` or `__try __finally` statement.
469+
*/
470+
private class TryOrMicrosoftTryStmt extends Stmt {
471+
TryOrMicrosoftTryStmt() {
472+
this instanceof TryStmt or
473+
this instanceof MicrosoftTryStmt
474+
}
475+
476+
/** Gets the number of `catch block`s of this statement. */
477+
int getNumberOfCatchClauses() {
478+
result = this.(TryStmt).getNumberOfCatchClauses()
479+
or
480+
this instanceof MicrosoftTryExceptStmt and
481+
result = 1
482+
or
483+
this instanceof MicrosoftTryFinallyStmt and
484+
result = 0
485+
}
486+
487+
/** Gets the `body` statement of this statement. */
488+
Stmt getStmt() {
489+
result = this.(TryStmt).getStmt()
490+
or
491+
result = this.(MicrosoftTryStmt).getStmt()
492+
}
493+
494+
/** Gets the `i`th translated handler of this statement. */
495+
TranslatedElement getTranslatedHandler(int index) {
496+
result = getTranslatedStmt(this.(TryStmt).getChild(index + 1))
497+
or
498+
index = 0 and
499+
result = getTranslatedMicrosoftTryExceptHandler(this)
500+
}
501+
502+
/** Gets the `finally` statement (usually a BlockStmt), if any. */
503+
Stmt getFinally() { result = this.(MicrosoftTryFinallyStmt).getFinally() }
504+
}
505+
506+
/**
507+
* The IR translation of a C++ `try` (or a `__try __except` or `__try __finally`) statement.
253508
*/
254509
class TranslatedTryStmt extends TranslatedStmt {
255-
override TryStmt stmt;
510+
override TryOrMicrosoftTryStmt stmt;
256511

257512
override TranslatedElement getChild(int id) {
258513
id = 0 and result = getBody()
259514
or
260515
result = getHandler(id - 1)
516+
or
517+
id = stmt.getNumberOfCatchClauses() + 1 and
518+
result = this.getFinally()
261519
}
262520

263521
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -269,8 +527,20 @@ class TranslatedTryStmt extends TranslatedStmt {
269527
override Instruction getFirstInstruction() { result = getBody().getFirstInstruction() }
270528

271529
override Instruction getChildSuccessor(TranslatedElement child) {
272-
// All children go to the successor of the `try`.
273-
child = getAChild() and result = getParent().getChildSuccessor(this)
530+
// All non-finally children go to the successor of the `try` if
531+
// there is no finally block, but if there is a finally block
532+
// then we go to that one.
533+
child = [this.getBody(), this.getHandler(_)] and
534+
(
535+
not exists(this.getFinally()) and
536+
result = this.getParent().getChildSuccessor(this)
537+
or
538+
result = this.getFinally().getFirstInstruction()
539+
)
540+
or
541+
// And after the finally block we go to the successor of the `try`.
542+
child = this.getFinally() and
543+
result = this.getParent().getChildSuccessor(this)
274544
}
275545

276546
final Instruction getNextHandler(TranslatedHandler handler) {
@@ -290,9 +560,9 @@ class TranslatedTryStmt extends TranslatedStmt {
290560
result = getHandler(0).getFirstInstruction()
291561
}
292562

293-
private TranslatedHandler getHandler(int index) {
294-
result = getTranslatedStmt(stmt.getChild(index + 1))
295-
}
563+
private TranslatedElement getHandler(int index) { result = stmt.getTranslatedHandler(index) }
564+
565+
private TranslatedStmt getFinally() { result = getTranslatedStmt(stmt.getFinally()) }
296566

297567
private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) }
298568
}

0 commit comments

Comments
 (0)