Skip to content

Commit 2d9df70

Browse files
authored
Merge pull request github#2887 from MathiasVP/fix-ir-gen-switch
C++: Fix IR generation for switch statements
2 parents 94aa777 + ed430ce commit 2d9df70

24 files changed

+532
-0
lines changed

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,16 @@ module InstructionSanity {
266266
funcText = Language::getIdentityString(func.getFunction())
267267
)
268268
}
269+
270+
query predicate switchInstructionWithoutDefaultEdge(
271+
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
272+
) {
273+
not exists(switchInstr.getDefaultSuccessor()) and
274+
message =
275+
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
276+
func = switchInstr.getEnclosingIRFunction() and
277+
funcText = Language::getIdentityString(func.getFunction())
278+
}
269279
}
270280

271281
/**

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,16 @@ module InstructionSanity {
266266
funcText = Language::getIdentityString(func.getFunction())
267267
)
268268
}
269+
270+
query predicate switchInstructionWithoutDefaultEdge(
271+
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
272+
) {
273+
not exists(switchInstr.getDefaultSuccessor()) and
274+
message =
275+
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
276+
func = switchInstr.getEnclosingIRFunction() and
277+
funcText = Language::getIdentityString(func.getFunction())
278+
}
269279
}
270280

271281
/**

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,11 @@ class TranslatedSwitchStmt extends TranslatedStmt {
655655
kind = getCaseEdge(switchCase) and
656656
result = getTranslatedStmt(switchCase).getFirstInstruction()
657657
)
658+
or
659+
not stmt.hasDefaultCase() and
660+
tag = SwitchBranchTag() and
661+
kind instanceof DefaultEdge and
662+
result = getParent().getChildSuccessor(this)
658663
}
659664

660665
override Instruction getChildSuccessor(TranslatedElement child) {

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,16 @@ module InstructionSanity {
266266
funcText = Language::getIdentityString(func.getFunction())
267267
)
268268
}
269+
270+
query predicate switchInstructionWithoutDefaultEdge(
271+
SwitchInstruction switchInstr, string message, IRFunction func, string funcText
272+
) {
273+
not exists(switchInstr.getDefaultSuccessor()) and
274+
message =
275+
"SwitchInstruction " + switchInstr.toString() + " without a DefaultEdge in function '$@'." and
276+
func = switchInstr.getEnclosingIRFunction() and
277+
funcText = Language::getIdentityString(func.getFunction())
278+
}
269279
}
270280

271281
/**

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

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8070,6 +8070,239 @@ ir.cpp:
80708070
# 1170| Type = [ArrayType] const char[4]
80718071
# 1170| Value = [StringLiteral] "foo"
80728072
# 1170| ValueCategory = lvalue
8073+
# 1173| [TopLevelFunction] void switch1Case(int)
8074+
# 1173| params:
8075+
# 1173| 0: [Parameter] x
8076+
# 1173| Type = [IntType] int
8077+
# 1173| body: [Block] { ... }
8078+
# 1174| 0: [DeclStmt] declaration
8079+
# 1174| 0: [VariableDeclarationEntry] definition of y
8080+
# 1174| Type = [IntType] int
8081+
# 1174| init: [Initializer] initializer for y
8082+
# 1174| expr: [Literal] 0
8083+
# 1174| Type = [IntType] int
8084+
# 1174| Value = [Literal] 0
8085+
# 1174| ValueCategory = prvalue
8086+
# 1175| 1: [SwitchStmt] switch (...) ...
8087+
# 1175| 0: [VariableAccess] x
8088+
# 1175| Type = [IntType] int
8089+
# 1175| ValueCategory = prvalue(load)
8090+
# 1175| 1: [Block] { ... }
8091+
# 1176| 0: [SwitchCase] case ...:
8092+
# 1176| 0: [Literal] 1
8093+
# 1176| Type = [IntType] int
8094+
# 1176| Value = [Literal] 1
8095+
# 1176| ValueCategory = prvalue
8096+
# 1177| 1: [ExprStmt] ExprStmt
8097+
# 1177| 0: [AssignExpr] ... = ...
8098+
# 1177| Type = [IntType] int
8099+
# 1177| ValueCategory = lvalue
8100+
# 1177| 0: [VariableAccess] y
8101+
# 1177| Type = [IntType] int
8102+
# 1177| ValueCategory = lvalue
8103+
# 1177| 1: [Literal] 2
8104+
# 1177| Type = [IntType] int
8105+
# 1177| Value = [Literal] 2
8106+
# 1177| ValueCategory = prvalue
8107+
# 1179| 2: [DeclStmt] declaration
8108+
# 1179| 0: [VariableDeclarationEntry] definition of z
8109+
# 1179| Type = [IntType] int
8110+
# 1179| init: [Initializer] initializer for z
8111+
# 1179| expr: [VariableAccess] y
8112+
# 1179| Type = [IntType] int
8113+
# 1179| ValueCategory = prvalue(load)
8114+
# 1180| 3: [ReturnStmt] return ...
8115+
# 1182| [TopLevelFunction] void switch2Case_fallthrough(int)
8116+
# 1182| params:
8117+
# 1182| 0: [Parameter] x
8118+
# 1182| Type = [IntType] int
8119+
# 1182| body: [Block] { ... }
8120+
# 1183| 0: [DeclStmt] declaration
8121+
# 1183| 0: [VariableDeclarationEntry] definition of y
8122+
# 1183| Type = [IntType] int
8123+
# 1183| init: [Initializer] initializer for y
8124+
# 1183| expr: [Literal] 0
8125+
# 1183| Type = [IntType] int
8126+
# 1183| Value = [Literal] 0
8127+
# 1183| ValueCategory = prvalue
8128+
# 1184| 1: [SwitchStmt] switch (...) ...
8129+
# 1184| 0: [VariableAccess] x
8130+
# 1184| Type = [IntType] int
8131+
# 1184| ValueCategory = prvalue(load)
8132+
# 1184| 1: [Block] { ... }
8133+
# 1185| 0: [SwitchCase] case ...:
8134+
# 1185| 0: [Literal] 1
8135+
# 1185| Type = [IntType] int
8136+
# 1185| Value = [Literal] 1
8137+
# 1185| ValueCategory = prvalue
8138+
# 1186| 1: [ExprStmt] ExprStmt
8139+
# 1186| 0: [AssignExpr] ... = ...
8140+
# 1186| Type = [IntType] int
8141+
# 1186| ValueCategory = lvalue
8142+
# 1186| 0: [VariableAccess] y
8143+
# 1186| Type = [IntType] int
8144+
# 1186| ValueCategory = lvalue
8145+
# 1186| 1: [Literal] 2
8146+
# 1186| Type = [IntType] int
8147+
# 1186| Value = [Literal] 2
8148+
# 1186| ValueCategory = prvalue
8149+
# 1187| 2: [SwitchCase] case ...:
8150+
# 1187| 0: [Literal] 2
8151+
# 1187| Type = [IntType] int
8152+
# 1187| Value = [Literal] 2
8153+
# 1187| ValueCategory = prvalue
8154+
# 1188| 3: [ExprStmt] ExprStmt
8155+
# 1188| 0: [AssignExpr] ... = ...
8156+
# 1188| Type = [IntType] int
8157+
# 1188| ValueCategory = lvalue
8158+
# 1188| 0: [VariableAccess] y
8159+
# 1188| Type = [IntType] int
8160+
# 1188| ValueCategory = lvalue
8161+
# 1188| 1: [Literal] 3
8162+
# 1188| Type = [IntType] int
8163+
# 1188| Value = [Literal] 3
8164+
# 1188| ValueCategory = prvalue
8165+
# 1190| 2: [DeclStmt] declaration
8166+
# 1190| 0: [VariableDeclarationEntry] definition of z
8167+
# 1190| Type = [IntType] int
8168+
# 1190| init: [Initializer] initializer for z
8169+
# 1190| expr: [VariableAccess] y
8170+
# 1190| Type = [IntType] int
8171+
# 1190| ValueCategory = prvalue(load)
8172+
# 1191| 3: [ReturnStmt] return ...
8173+
# 1193| [TopLevelFunction] void switch2Case(int)
8174+
# 1193| params:
8175+
# 1193| 0: [Parameter] x
8176+
# 1193| Type = [IntType] int
8177+
# 1193| body: [Block] { ... }
8178+
# 1194| 0: [DeclStmt] declaration
8179+
# 1194| 0: [VariableDeclarationEntry] definition of y
8180+
# 1194| Type = [IntType] int
8181+
# 1194| init: [Initializer] initializer for y
8182+
# 1194| expr: [Literal] 0
8183+
# 1194| Type = [IntType] int
8184+
# 1194| Value = [Literal] 0
8185+
# 1194| ValueCategory = prvalue
8186+
# 1195| 1: [SwitchStmt] switch (...) ...
8187+
# 1195| 0: [VariableAccess] x
8188+
# 1195| Type = [IntType] int
8189+
# 1195| ValueCategory = prvalue(load)
8190+
# 1195| 1: [Block] { ... }
8191+
# 1196| 0: [SwitchCase] case ...:
8192+
# 1196| 0: [Literal] 1
8193+
# 1196| Type = [IntType] int
8194+
# 1196| Value = [Literal] 1
8195+
# 1196| ValueCategory = prvalue
8196+
# 1197| 1: [ExprStmt] ExprStmt
8197+
# 1197| 0: [AssignExpr] ... = ...
8198+
# 1197| Type = [IntType] int
8199+
# 1197| ValueCategory = lvalue
8200+
# 1197| 0: [VariableAccess] y
8201+
# 1197| Type = [IntType] int
8202+
# 1197| ValueCategory = lvalue
8203+
# 1197| 1: [Literal] 2
8204+
# 1197| Type = [IntType] int
8205+
# 1197| Value = [Literal] 2
8206+
# 1197| ValueCategory = prvalue
8207+
# 1198| 2: [BreakStmt] break;
8208+
# 1199| 3: [SwitchCase] case ...:
8209+
# 1199| 0: [Literal] 2
8210+
# 1199| Type = [IntType] int
8211+
# 1199| Value = [Literal] 2
8212+
# 1199| ValueCategory = prvalue
8213+
# 1200| 4: [ExprStmt] ExprStmt
8214+
# 1200| 0: [AssignExpr] ... = ...
8215+
# 1200| Type = [IntType] int
8216+
# 1200| ValueCategory = lvalue
8217+
# 1200| 0: [VariableAccess] y
8218+
# 1200| Type = [IntType] int
8219+
# 1200| ValueCategory = lvalue
8220+
# 1200| 1: [Literal] 3
8221+
# 1200| Type = [IntType] int
8222+
# 1200| Value = [Literal] 3
8223+
# 1200| ValueCategory = prvalue
8224+
# 1201| 2: [LabelStmt] label ...:
8225+
# 1202| 3: [DeclStmt] declaration
8226+
# 1202| 0: [VariableDeclarationEntry] definition of z
8227+
# 1202| Type = [IntType] int
8228+
# 1202| init: [Initializer] initializer for z
8229+
# 1202| expr: [VariableAccess] y
8230+
# 1202| Type = [IntType] int
8231+
# 1202| ValueCategory = prvalue(load)
8232+
# 1203| 4: [ReturnStmt] return ...
8233+
# 1205| [TopLevelFunction] void switch2Case_default(int)
8234+
# 1205| params:
8235+
# 1205| 0: [Parameter] x
8236+
# 1205| Type = [IntType] int
8237+
# 1205| body: [Block] { ... }
8238+
# 1206| 0: [DeclStmt] declaration
8239+
# 1206| 0: [VariableDeclarationEntry] definition of y
8240+
# 1206| Type = [IntType] int
8241+
# 1206| init: [Initializer] initializer for y
8242+
# 1206| expr: [Literal] 0
8243+
# 1206| Type = [IntType] int
8244+
# 1206| Value = [Literal] 0
8245+
# 1206| ValueCategory = prvalue
8246+
# 1207| 1: [SwitchStmt] switch (...) ...
8247+
# 1207| 0: [VariableAccess] x
8248+
# 1207| Type = [IntType] int
8249+
# 1207| ValueCategory = prvalue(load)
8250+
# 1207| 1: [Block] { ... }
8251+
# 1208| 0: [SwitchCase] case ...:
8252+
# 1208| 0: [Literal] 1
8253+
# 1208| Type = [IntType] int
8254+
# 1208| Value = [Literal] 1
8255+
# 1208| ValueCategory = prvalue
8256+
# 1209| 1: [ExprStmt] ExprStmt
8257+
# 1209| 0: [AssignExpr] ... = ...
8258+
# 1209| Type = [IntType] int
8259+
# 1209| ValueCategory = lvalue
8260+
# 1209| 0: [VariableAccess] y
8261+
# 1209| Type = [IntType] int
8262+
# 1209| ValueCategory = lvalue
8263+
# 1209| 1: [Literal] 2
8264+
# 1209| Type = [IntType] int
8265+
# 1209| Value = [Literal] 2
8266+
# 1209| ValueCategory = prvalue
8267+
# 1210| 2: [BreakStmt] break;
8268+
# 1212| 3: [SwitchCase] case ...:
8269+
# 1212| 0: [Literal] 2
8270+
# 1212| Type = [IntType] int
8271+
# 1212| Value = [Literal] 2
8272+
# 1212| ValueCategory = prvalue
8273+
# 1213| 4: [ExprStmt] ExprStmt
8274+
# 1213| 0: [AssignExpr] ... = ...
8275+
# 1213| Type = [IntType] int
8276+
# 1213| ValueCategory = lvalue
8277+
# 1213| 0: [VariableAccess] y
8278+
# 1213| Type = [IntType] int
8279+
# 1213| ValueCategory = lvalue
8280+
# 1213| 1: [Literal] 3
8281+
# 1213| Type = [IntType] int
8282+
# 1213| Value = [Literal] 3
8283+
# 1213| ValueCategory = prvalue
8284+
# 1214| 5: [BreakStmt] break;
8285+
# 1216| 6: [SwitchCase] default:
8286+
# 1217| 7: [ExprStmt] ExprStmt
8287+
# 1217| 0: [AssignExpr] ... = ...
8288+
# 1217| Type = [IntType] int
8289+
# 1217| ValueCategory = lvalue
8290+
# 1217| 0: [VariableAccess] y
8291+
# 1217| Type = [IntType] int
8292+
# 1217| ValueCategory = lvalue
8293+
# 1217| 1: [Literal] 4
8294+
# 1217| Type = [IntType] int
8295+
# 1217| Value = [Literal] 4
8296+
# 1217| ValueCategory = prvalue
8297+
# 1218| 2: [LabelStmt] label ...:
8298+
# 1219| 3: [DeclStmt] declaration
8299+
# 1219| 0: [VariableDeclarationEntry] definition of z
8300+
# 1219| Type = [IntType] int
8301+
# 1219| init: [Initializer] initializer for z
8302+
# 1219| expr: [VariableAccess] y
8303+
# 1219| Type = [IntType] int
8304+
# 1219| ValueCategory = prvalue(load)
8305+
# 1220| 4: [ReturnStmt] return ...
80738306
perf-regression.cpp:
80748307
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
80758308
# 4| params:

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
1919
lostReachability
2020
backEdgeCountMismatch
2121
useNotDominatedByDefinition
22+
switchInstructionWithoutDefaultEdge
2223
missingCanonicalLanguageType
2324
multipleCanonicalLanguageTypes
2425
missingIRType

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ containsLoopOfForwardEdges
1919
lostReachability
2020
backEdgeCountMismatch
2121
useNotDominatedByDefinition
22+
switchInstructionWithoutDefaultEdge
2223
missingCanonicalLanguageType
2324
multipleCanonicalLanguageTypes
2425
missingIRType

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,4 +1170,53 @@ String ReturnObjectImpl() {
11701170
return String("foo");
11711171
}
11721172

1173+
void switch1Case(int x) {
1174+
int y = 0;
1175+
switch(x) {
1176+
case 1:
1177+
y = 2;
1178+
}
1179+
int z = y;
1180+
}
1181+
1182+
void switch2Case_fallthrough(int x) {
1183+
int y = 0;
1184+
switch(x) {
1185+
case 1:
1186+
y = 2;
1187+
case 2:
1188+
y = 3;
1189+
}
1190+
int z = y;
1191+
}
1192+
1193+
void switch2Case(int x) {
1194+
int y = 0;
1195+
switch(x) {
1196+
case 1:
1197+
y = 2;
1198+
break;
1199+
case 2:
1200+
y = 3;
1201+
}
1202+
int z = y;
1203+
}
1204+
1205+
void switch2Case_default(int x) {
1206+
int y = 0;
1207+
switch(x) {
1208+
case 1:
1209+
y = 2;
1210+
break;
1211+
1212+
case 2:
1213+
y = 3;
1214+
break;
1215+
1216+
default:
1217+
y = 4;
1218+
}
1219+
int z = y;
1220+
}
1221+
11731222
// semmle-extractor-options: -std=c++17 --clang

0 commit comments

Comments
 (0)