Skip to content

Commit ff6e8a2

Browse files
committed
C++: Model semantics of '__except' condition in IR.
1 parent e6a03a6 commit ff6e8a2

File tree

6 files changed

+287
-18
lines changed

6 files changed

+287
-18
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: 222 additions & 8 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 = 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 = getTranslatedCondition().getResult()
91+
or
92+
operandTag instanceof RightOperandTag and
93+
result = getInstruction(TryExceptGenerateNegativeOne())
94+
)
95+
or
96+
tag = TryExceptCompareNegativeOneBranch() and
97+
operandTag instanceof ConditionOperandTag and
98+
result = getInstruction(TryExceptCompareNegativeOne())
99+
or
100+
tag = TryExceptCompareZero() and
101+
(
102+
operandTag instanceof LeftOperandTag and
103+
result = getTranslatedCondition().getResult()
104+
or
105+
operandTag instanceof RightOperandTag and
106+
result = getInstruction(TryExceptGenerateZero())
107+
)
108+
or
109+
tag = TryExceptCompareZeroBranch() and
110+
operandTag instanceof ConditionOperandTag and
111+
result = getInstruction(TryExceptCompareZero())
112+
or
113+
tag = TryExceptCompareOne() and
114+
(
115+
operandTag instanceof LeftOperandTag and
116+
result = getTranslatedCondition().getResult()
117+
or
118+
operandTag instanceof RightOperandTag and
119+
result = getInstruction(TryExceptGenerateOne())
120+
)
121+
or
122+
tag = TryExceptCompareOneBranch() and
123+
operandTag instanceof ConditionOperandTag and
124+
result = 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 = getInstruction(TryExceptCompareNegativeOne())
143+
or
144+
// Compare condition -> Branch
145+
tag = TryExceptCompareNegativeOne() and
146+
kind instanceof GotoEdge and
147+
result = 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 = getInstruction(UnwindTag())
157+
or
158+
kind instanceof FalseEdge and
159+
result = getInstruction(TryExceptGenerateZero())
160+
)
161+
or
162+
// Generate 0 -> Compare condition
163+
tag = TryExceptGenerateZero() and
164+
kind instanceof GotoEdge and
165+
result = getInstruction(TryExceptCompareZero())
166+
or
167+
// Compare condition -> Branch
168+
tag = TryExceptCompareZero() and
169+
kind instanceof GotoEdge and
170+
result = getInstruction(TryExceptCompareZeroBranch())
171+
or
172+
// Branch -> Unwind or Generate 1
173+
tag = TryExceptCompareZeroBranch() and
174+
(
175+
kind instanceof TrueEdge and
176+
result = getInstruction(UnwindTag())
177+
or
178+
kind instanceof FalseEdge and
179+
result = getInstruction(TryExceptGenerateOne())
180+
)
181+
or
182+
// Generate 1 -> Compare condition
183+
tag = TryExceptGenerateOne() and
184+
kind instanceof GotoEdge and
185+
result = getInstruction(TryExceptCompareOne())
186+
or
187+
// Compare condition -> Branch
188+
tag = TryExceptCompareOne() and
189+
kind instanceof GotoEdge and
190+
result = 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 = getTranslatedHandler().getFirstInstruction()
197+
)
198+
or
199+
// Unwind -> Parent
200+
tag = UnwindTag() and
201+
kind instanceof GotoEdge and
202+
result = getParent().getChildSuccessor(this)
203+
}
204+
205+
override Instruction getChildSuccessor(TranslatedElement child) {
206+
child = getTranslatedCondition() and
207+
result = getInstruction(TryExceptGenerateNegativeOne())
208+
or
209+
child = getTranslatedHandler() and
210+
result = 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 = getTranslatedCondition()
224+
or
225+
id = 1 and
226+
result = getTranslatedHandler()
227+
}
228+
229+
final override Function getFunction() { result = tryExcept.getEnclosingFunction() }
230+
}
231+
16232
abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
17233
Stmt stmt;
18234

@@ -275,12 +491,12 @@ private class TryOrMicrosoftTryStmt extends Stmt {
275491
result = this.(MicrosoftTryStmt).getStmt()
276492
}
277493

278-
/** Gets the `i`th `catch block` statement of this statement. */
279-
Stmt getHandlerStmt(int i) {
280-
result = this.(TryStmt).getChild(i + 1)
494+
/** Gets the `i`th translated handler of this statement. */
495+
TranslatedElement getTranslatedHandler(int index) {
496+
result = getTranslatedStmt(this.(TryStmt).getChild(index + 1))
281497
or
282-
i = 0 and
283-
result = this.(MicrosoftTryExceptStmt).getExcept()
498+
index = 0 and
499+
result = getTranslatedMicrosoftTryExceptHandler(this)
284500
}
285501

286502
/** Gets the `finally` statement (usually a BlockStmt), if any. */
@@ -344,9 +560,7 @@ class TranslatedTryStmt extends TranslatedStmt {
344560
result = getHandler(0).getFirstInstruction()
345561
}
346562

347-
private TranslatedStmt getHandler(int index) {
348-
result = getTranslatedStmt(stmt.getHandlerStmt(index))
349-
}
563+
private TranslatedElement getHandler(int index) { result = stmt.getTranslatedHandler(index) }
350564

351565
private TranslatedStmt getFinally() { result = getTranslatedStmt(stmt.getFinally()) }
352566

cpp/ql/test/library-tests/ir/ir/raw_consistency.expected

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ missingOperandType
66
duplicateChiOperand
77
sideEffectWithoutPrimary
88
instructionWithoutSuccessor
9-
| try_except.c:13:13:13:13 | Constant: 0 | Instruction 'Constant: 0' has no successors in function '$@'. | try_except.c:6:6:6:6 | void f() | void f() |
109
ambiguousSuccessors
1110
unexplainedLoop
1211
unnecessaryPhiInstruction
@@ -20,6 +19,8 @@ useNotDominatedByDefinition
2019
| ir.cpp:1486:8:1486:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1486:8:1486:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() |
2120
| ir.cpp:1751:51:1751:51 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1750:5:1750:34 | int implicit_copy_constructor_test(CopyConstructorTestNonVirtualClass const&, CopyConstructorTestVirtualClass const&) | int implicit_copy_constructor_test(CopyConstructorTestNonVirtualClass const&, CopyConstructorTestVirtualClass const&) |
2221
| ir.cpp:1752:48:1752:48 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1750:5:1750:34 | int implicit_copy_constructor_test(CopyConstructorTestNonVirtualClass const&, CopyConstructorTestVirtualClass const&) | int implicit_copy_constructor_test(CopyConstructorTestNonVirtualClass const&, CopyConstructorTestVirtualClass const&) |
22+
| try_except.c:13:13:13:13 | Left | Operand 'Left' is not dominated by its definition in function '$@'. | try_except.c:6:6:6:6 | void f() | void f() |
23+
| try_except.c:13:13:13:13 | Left | Operand 'Left' is not dominated by its definition in function '$@'. | try_except.c:6:6:6:6 | void f() | void f() |
2324
switchInstructionWithoutDefaultEdge
2425
notMarkedAsConflated
2526
wronglyMarkedAsConflated

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

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10434,20 +10434,42 @@ try_except.c:
1043410434
# 11| r11_2(int) = Constant[0] :
1043510435
# 11| v11_3(void) = Call[ProbeFunction] : func:r11_1, 0:r11_2
1043610436
# 11| mu11_4(unknown) = ^CallSideEffect : ~m?
10437-
#-----| Goto -> Block 3
10437+
#-----| Goto -> Block 6
1043810438

1043910439
# 13| Block 1
10440-
# 13| r13_1(int) = Constant[0] :
10440+
# 13| r13_1(int) = Constant[0] :
10441+
# 13| r13_2(bool) = CompareEQ : r13_8, r13_1
10442+
# 13| v13_3(void) = ConditionalBranch : r13_2
10443+
#-----| False -> Block 2
10444+
#-----| True -> Block 3
1044110445

10442-
# 14| Block 2
10446+
# 13| Block 2
10447+
# 13| r13_4(int) = Constant[1] :
10448+
# 13| r13_5(bool) = CompareEQ : r13_8, r13_4
10449+
# 13| v13_6(void) = ConditionalBranch : r13_5
10450+
#-----| True -> Block 5
10451+
10452+
# 13| Block 3
10453+
# 13| v13_7(void) = Unwind :
10454+
#-----| Goto -> Block 6
10455+
10456+
# 13| Block 4
10457+
# 13| r13_8(int) = Constant[0] :
10458+
# 13| r13_9(int) = Constant[-1] :
10459+
# 13| r13_10(bool) = CompareEQ : r13_8, r13_9
10460+
# 13| v13_11(void) = ConditionalBranch : r13_10
10461+
#-----| False -> Block 1
10462+
#-----| True -> Block 3
10463+
10464+
# 14| Block 5
1044310465
# 14| r14_1(glval<unknown>) = FunctionAddress[sink] :
1044410466
# 14| r14_2(glval<int>) = VariableAddress[x] :
1044510467
# 14| r14_3(int) = Load[x] : &:r14_2, ~m?
1044610468
# 14| v14_4(void) = Call[sink] : func:r14_1, 0:r14_3
1044710469
# 14| mu14_5(unknown) = ^CallSideEffect : ~m?
10448-
#-----| Goto -> Block 3
10470+
#-----| Goto -> Block 6
1044910471

10450-
# 16| Block 3
10472+
# 16| Block 6
1045110473
# 16| v16_1(void) = NoOp :
1045210474
# 6| v6_4(void) = ReturnVoid :
1045310475
# 6| v6_5(void) = AliasedUse : ~m?

cpp/ql/test/library-tests/syntax-zoo/raw_consistency.expected

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ instructionWithoutSuccessor
3131
| misc.c:174:17:174:22 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
3232
| misc.c:174:30:174:35 | CallSideEffect: call to getInt | Instruction 'CallSideEffect: call to getInt' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
3333
| misc.c:174:55:174:60 | Store: (char ****)... | Instruction 'Store: (char ****)...' has no successors in function '$@'. | misc.c:168:6:168:8 | void vla() | void vla() |
34-
| ms_try_except.cpp:9:19:9:19 | Load: j | Instruction 'Load: j' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) |
35-
| ms_try_except.cpp:19:17:19:21 | Sub: ... - ... | Instruction 'Sub: ... - ...' has no successors in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) |
36-
| ms_try_mix.cpp:20:15:20:39 | Constant: 1 | Instruction 'Constant: 1' has no successors in function '$@'. | ms_try_mix.cpp:10:6:10:18 | void ms_except_mix(int) | void ms_except_mix(int) |
3734
| ms_try_mix.cpp:33:13:33:19 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:27:6:27:19 | void ms_finally_mix(int) | void ms_finally_mix(int) |
3835
| ms_try_mix.cpp:51:5:51:11 | ThrowValue: throw ... | Instruction 'ThrowValue: throw ...' has no successors in function '$@'. | ms_try_mix.cpp:47:6:47:28 | void ms_empty_finally_at_end() | void ms_empty_finally_at_end() |
3936
| stmt_expr.cpp:27:5:27:15 | Store: ... = ... | Instruction 'Store: ... = ...' has no successors in function '$@'. | stmt_expr.cpp:21:6:21:6 | void stmtexpr::g(int) | void stmtexpr::g(int) |
@@ -120,6 +117,10 @@ backEdgeCountMismatch
120117
useNotDominatedByDefinition
121118
| VacuousDestructorCall.cpp:2:29:2:29 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | VacuousDestructorCall.cpp:2:6:2:6 | void CallDestructor<int>(int, int*) | void CallDestructor<int>(int, int*) |
122119
| misc.c:219:47:219:48 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) |
120+
| ms_try_except.cpp:9:19:9:19 | Left | Operand 'Left' is not dominated by its definition in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) |
121+
| ms_try_except.cpp:9:19:9:19 | Left | Operand 'Left' is not dominated by its definition in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) |
122+
| ms_try_except.cpp:19:17:19:21 | Left | Operand 'Left' is not dominated by its definition in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) |
123+
| ms_try_except.cpp:19:17:19:21 | Left | Operand 'Left' is not dominated by its definition in function '$@'. | ms_try_except.cpp:2:6:2:18 | void ms_try_except(int) | void ms_try_except(int) |
123124
| static_init_templates.cpp:15:1:15:18 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | static_init_templates.cpp:15:1:15:18 | void MyClass::MyClass() | void MyClass::MyClass() |
124125
| try_catch.cpp:21:9:21:9 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | try_catch.cpp:19:6:19:23 | void throw_from_nonstmt(int) | void throw_from_nonstmt(int) |
125126
| vla.c:3:27:3:30 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | vla.c:3:5:3:8 | int main(int, char**) | int main(int, char**) |

0 commit comments

Comments
 (0)