Skip to content

Commit 912679e

Browse files
C++: Two IR fixes
My original fix in #1661 fixed my minimal test case, but did not fix the original failure in a Linux snapshot. The real fix is to simply not create a `TranslatedDeclarationEntry` for an extern declaration, and have `TranslatedDeclStmt` skip any such declarations. I've added a regression test for that case (multiple extern declarations with same location in a macro expansion, with control flow between them). I did verify that it generates correct IR, and that it fixes all of the "use not dominated by definition" failures in Linux. The underlying extractor bug, that caused the above issue also caused PrintAST to print garbage. I've worked around the bug in PrintAST.qll. I've also fixed a bug in the control flow for `try`/`catch`, where there was missing flow from the `CatchByType` of the last handler of a `try` to the enclosing handler (or `Unwind`). Hat tip to @andreidiaconu1 for spotting this bug.
1 parent 691df05 commit 912679e

File tree

7 files changed

+362
-61
lines changed

7 files changed

+362
-61
lines changed

cpp/ql/src/semmle/code/cpp/PrintAST.qll

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,6 @@ private Function getEnclosingFunction(Locatable ast) {
6767
or
6868
result = ast.(Parameter).getFunction()
6969
or
70-
exists(DeclStmt stmt |
71-
stmt.getADeclarationEntry() = ast and
72-
result = stmt.getEnclosingFunction()
73-
)
74-
or
7570
result = ast
7671
}
7772

@@ -80,7 +75,14 @@ private Function getEnclosingFunction(Locatable ast) {
8075
* nodes for things like parameter lists and constructor init lists.
8176
*/
8277
private newtype TPrintASTNode =
83-
TASTNode(Locatable ast) { shouldPrintFunction(getEnclosingFunction(ast)) } or
78+
TASTNode(Locatable ast) {
79+
shouldPrintFunction(getEnclosingFunction(ast))
80+
} or
81+
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
82+
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
83+
// multiple parents due to extractor bug CPP-413.
84+
stmt.getADeclarationEntry() = entry
85+
} or
8486
TParametersNode(Function func) { shouldPrintFunction(func) } or
8587
TConstructorInitializersNode(Constructor ctor) {
8688
ctor.hasEntryPoint() and
@@ -161,11 +163,9 @@ private string qlClass(ElementBase el) { result = "[" + concat(el.getCanonicalQL
161163
/**
162164
* A node representing an AST node.
163165
*/
164-
abstract class ASTNode extends PrintASTNode, TASTNode {
166+
abstract class BaseASTNode extends PrintASTNode {
165167
Locatable ast;
166168

167-
ASTNode() { this = TASTNode(ast) }
168-
169169
override string toString() { result = qlClass(ast) + ast.toString() }
170170

171171
final override Location getLocation() { result = getRepresentativeLocation(ast) }
@@ -176,6 +176,13 @@ abstract class ASTNode extends PrintASTNode, TASTNode {
176176
final Locatable getAST() { result = ast }
177177
}
178178

179+
/**
180+
* A node representing an AST node other than a `DeclarationEntry`.
181+
*/
182+
abstract class ASTNode extends BaseASTNode, TASTNode {
183+
ASTNode() { this = TASTNode(ast) }
184+
}
185+
179186
/**
180187
* A node representing an `Expr`.
181188
*/
@@ -250,32 +257,33 @@ class CastNode extends ConversionNode {
250257
/**
251258
* A node representing a `DeclarationEntry`.
252259
*/
253-
class DeclarationEntryNode extends ASTNode {
254-
DeclarationEntry entry;
260+
class DeclarationEntryNode extends BaseASTNode, TDeclarationEntryNode {
261+
override DeclarationEntry ast;
262+
DeclStmt declStmt;
255263

256-
DeclarationEntryNode() { entry = ast }
264+
DeclarationEntryNode() {
265+
this = TDeclarationEntryNode(declStmt, ast)
266+
}
257267

258268
override PrintASTNode getChild(int childIndex) { none() }
259269

260270
override string getProperty(string key) {
261-
result = super.getProperty(key)
271+
result = BaseASTNode.super.getProperty(key)
262272
or
263273
key = "Type" and
264-
result = qlClass(entry.getType()) + entry.getType().toString()
274+
result = qlClass(ast.getType()) + ast.getType().toString()
265275
}
266276
}
267277

268278
/**
269279
* A node representing a `VariableDeclarationEntry`.
270280
*/
271281
class VariableDeclarationEntryNode extends DeclarationEntryNode {
272-
VariableDeclarationEntry varEntry;
273-
274-
VariableDeclarationEntryNode() { varEntry = entry }
282+
override VariableDeclarationEntry ast;
275283

276284
override ASTNode getChild(int childIndex) {
277285
childIndex = 0 and
278-
result.getAST() = varEntry.getVariable().getInitializer()
286+
result.getAST() = ast.getVariable().getInitializer()
279287
}
280288

281289
override string getChildEdgeLabel(int childIndex) { childIndex = 0 and result = "init" }
@@ -289,7 +297,7 @@ class StmtNode extends ASTNode {
289297

290298
StmtNode() { stmt = ast }
291299

292-
override ASTNode getChild(int childIndex) {
300+
override BaseASTNode getChild(int childIndex) {
293301
exists(Locatable child |
294302
child = stmt.getChild(childIndex) and
295303
(
@@ -308,8 +316,11 @@ class DeclStmtNode extends StmtNode {
308316

309317
DeclStmtNode() { declStmt = stmt }
310318

311-
override ASTNode getChild(int childIndex) {
312-
result.getAST() = declStmt.getDeclarationEntry(childIndex)
319+
override DeclarationEntryNode getChild(int childIndex) {
320+
exists (DeclarationEntry entry |
321+
declStmt.getDeclarationEntry(childIndex) = entry and
322+
result = TDeclarationEntryNode(declStmt, entry)
323+
)
313324
}
314325
}
315326

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

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ TranslatedDeclarationEntry getTranslatedDeclarationEntry(DeclarationEntry entry)
1818
/**
1919
* Represents the IR translation of a declaration within the body of a function.
2020
* Most often, this is the declaration of an automatic local variable, although
21-
* it can also be the declaration of a static local variable, an extern
22-
* variable, or an extern function.
21+
* it can also be the declaration of a static local variable. Declarations of extern variables and
22+
* functions do not have a `TranslatedDeclarationEntry`.
2323
*/
2424
abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslatedDeclarationEntry {
2525
DeclarationEntry entry;
@@ -44,39 +44,6 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
4444
}
4545
}
4646

47-
/**
48-
* Represents the IR translation of a declaration within the body of a function,
49-
* for declarations other than local variables. Since these have no semantic
50-
* effect, they do not generate any instructions.
51-
*/
52-
class TranslatedNonVariableDeclarationEntry extends TranslatedDeclarationEntry {
53-
TranslatedNonVariableDeclarationEntry() {
54-
not entry.getDeclaration() instanceof LocalVariable
55-
}
56-
57-
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
58-
Type resultType, boolean isGLValue) {
59-
none()
60-
}
61-
62-
override Instruction getFirstInstruction() {
63-
result = getParent().getChildSuccessor(this)
64-
}
65-
66-
override TranslatedElement getChild(int id) {
67-
none()
68-
}
69-
70-
override Instruction getInstructionSuccessor(InstructionTag tag,
71-
EdgeKind kind) {
72-
none()
73-
}
74-
75-
override Instruction getChildSuccessor(TranslatedElement child) {
76-
none()
77-
}
78-
}
79-
8047
/**
8148
* Represents the IR translation of the declaration of a local variable,
8249
* including its initialization, if any.

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,9 @@ newtype TTranslatedElement =
376376
TTranslatedDeclarationEntry(DeclarationEntry entry) {
377377
exists(DeclStmt declStmt |
378378
translateStmt(declStmt) and
379-
declStmt.getADeclarationEntry() = entry
379+
declStmt.getADeclarationEntry() = entry and
380+
// Only declarations of local variables need to be translated to IR.
381+
entry.getDeclaration() instanceof LocalVariable
380382
)
381383
} or
382384
// A compiler-generated variable to implement a range-based for loop. These don't have a

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

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ class TranslatedEmptyStmt extends TranslatedStmt {
6969
}
7070
}
7171

72+
/**
73+
* The IR translation of a declaration statement. This consists of the IR for each of the individual
74+
* local variables declared by the statement. Declarations for extern variables and functions
75+
* do not generate any instructions.
76+
*/
7277
class TranslatedDeclStmt extends TranslatedStmt {
7378
override DeclStmt stmt;
7479

@@ -82,15 +87,25 @@ class TranslatedDeclStmt extends TranslatedStmt {
8287
}
8388

8489
override Instruction getFirstInstruction() {
85-
result = getDeclarationEntry(0).getFirstInstruction() //REVIEW: Empty?
90+
result = getDeclarationEntry(0).getFirstInstruction() or
91+
not exists(getDeclarationEntry(0)) and result = getParent().getChildSuccessor(this)
8692
}
8793

8894
private int getChildCount() {
89-
result = stmt.getNumDeclarations()
95+
result = count(getDeclarationEntry(_))
9096
}
9197

98+
/**
99+
* Gets the `TranslatedDeclarationEntry` child at zero-based index `index`. Since not all
100+
* `DeclarationEntry` objects have a `TranslatedDeclarationEntry` (e.g. extern functions), we map
101+
* the original children into a contiguous range containing only those with an actual
102+
* `TranslatedDeclarationEntry`.
103+
*/
92104
private TranslatedDeclarationEntry getDeclarationEntry(int index) {
93-
result = getTranslatedDeclarationEntry(stmt.getDeclarationEntry(index))
105+
result = rank[index + 1](TranslatedDeclarationEntry entry, int originalIndex |
106+
entry = getTranslatedDeclarationEntry(stmt.getDeclarationEntry(originalIndex)) |
107+
entry order by originalIndex
108+
)
94109
}
95110

96111
override Instruction getInstructionSuccessor(InstructionTag tag,
@@ -273,7 +288,7 @@ class TranslatedTryStmt extends TranslatedStmt {
273288
// The last catch clause flows to the exception successor of the parent
274289
// of the `try`, because the exception successor of the `try` itself is
275290
// the first catch clause.
276-
handler = getHandler(stmt.getNumberOfCatchClauses()) and
291+
handler = getHandler(stmt.getNumberOfCatchClauses() - 1) and
277292
result = getParent().getExceptionSuccessorInstruction()
278293
)
279294
}

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

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7865,3 +7865,139 @@ ir.cpp:
78657865
# 1118| params:
78667866
# 1118| 0: [Parameter] p#0
78677867
# 1118| Type = [FloatType] float
7868+
# 1128| [TopLevelFunction] void ExternDeclarationsInMacro()
7869+
# 1128| params:
7870+
# 1129| body: [Block] { ... }
7871+
# 1130| 0: [DeclStmt] declaration
7872+
# 1130| 0: [VariableDeclarationEntry] declaration of g
7873+
# 1130| Type = [IntType] int
7874+
# 1130| 1: [ForStmt] for(...;...;...) ...
7875+
# 1130| 0: [DeclStmt] declaration
7876+
# 1130| 0: [VariableDeclarationEntry] definition of i
7877+
# 1130| Type = [IntType] int
7878+
# 1130| init: [Initializer] initializer for i
7879+
# 1130| expr: [Literal,Zero] 0
7880+
# 1130| Type = [IntType] int
7881+
# 1130| Value = [Literal,Zero] 0
7882+
# 1130| ValueCategory = prvalue
7883+
# 1130| 1: [LTExpr] ... < ...
7884+
# 1130| Type = [BoolType] bool
7885+
# 1130| ValueCategory = prvalue
7886+
# 1130| 0: [VariableAccess] i
7887+
# 1130| Type = [IntType] int
7888+
# 1130| ValueCategory = prvalue(load)
7889+
# 1130| 1: [Literal] 10
7890+
# 1130| Type = [IntType] int
7891+
# 1130| Value = [Literal] 10
7892+
# 1130| ValueCategory = prvalue
7893+
# 1130| 2: [PrefixIncrExpr] ++ ...
7894+
# 1130| Type = [IntType] int
7895+
# 1130| ValueCategory = lvalue
7896+
# 1130| 0: [VariableAccess] i
7897+
# 1130| Type = [IntType] int
7898+
# 1130| ValueCategory = lvalue
7899+
# 1130| 3: [Block] { ... }
7900+
# 1130| 0: [DeclStmt] declaration
7901+
# 1130| 0: [VariableDeclarationEntry] declaration of g
7902+
# 1130| Type = [IntType] int
7903+
# 1130| 2: [EmptyStmt] ;
7904+
# 1131| 3: [ReturnStmt] return ...
7905+
# 1133| [TopLevelFunction] void TryCatchNoCatchAny(bool)
7906+
# 1133| params:
7907+
# 1133| 0: [Parameter] b
7908+
# 1133| Type = [BoolType] bool
7909+
# 1133| body: [Block] { ... }
7910+
# 1134| 0: [TryStmt] try { ... }
7911+
# 1134| 0: [Block] { ... }
7912+
# 1135| 0: [DeclStmt] declaration
7913+
# 1135| 0: [VariableDeclarationEntry] definition of x
7914+
# 1135| Type = [IntType] int
7915+
# 1135| init: [Initializer] initializer for x
7916+
# 1135| expr: [Literal] 5
7917+
# 1135| Type = [IntType] int
7918+
# 1135| Value = [Literal] 5
7919+
# 1135| ValueCategory = prvalue
7920+
# 1136| 1: [IfStmt] if (...) ...
7921+
# 1136| 0: [VariableAccess] b
7922+
# 1136| Type = [BoolType] bool
7923+
# 1136| ValueCategory = prvalue(load)
7924+
# 1136| 1: [Block] { ... }
7925+
# 1137| 0: [ExprStmt] ExprStmt
7926+
# 1137| 0: [ThrowExpr] throw ...
7927+
# 1137| Type = [PointerType] const char *
7928+
# 1137| ValueCategory = prvalue
7929+
# 1137| 0: [ArrayToPointerConversion] array to pointer conversion
7930+
# 1137| Type = [PointerType] const char *
7931+
# 1137| ValueCategory = prvalue
7932+
# 1137| expr: string literal
7933+
# 1137| Type = [ArrayType] const char[15]
7934+
# 1137| Value = [StringLiteral] "string literal"
7935+
# 1137| ValueCategory = lvalue
7936+
# 1139| 2: [IfStmt] if (...) ...
7937+
# 1139| 0: [LTExpr] ... < ...
7938+
# 1139| Type = [BoolType] bool
7939+
# 1139| ValueCategory = prvalue
7940+
# 1139| 0: [VariableAccess] x
7941+
# 1139| Type = [IntType] int
7942+
# 1139| ValueCategory = prvalue(load)
7943+
# 1139| 1: [Literal] 2
7944+
# 1139| Type = [IntType] int
7945+
# 1139| Value = [Literal] 2
7946+
# 1139| ValueCategory = prvalue
7947+
# 1139| 1: [Block] { ... }
7948+
# 1140| 0: [ExprStmt] ExprStmt
7949+
# 1140| 0: [AssignExpr] ... = ...
7950+
# 1140| Type = [IntType] int
7951+
# 1140| ValueCategory = lvalue
7952+
# 1140| 0: [VariableAccess] x
7953+
# 1140| Type = [IntType] int
7954+
# 1140| ValueCategory = lvalue
7955+
# 1140| 1: [ConditionalExpr] ... ? ... : ...
7956+
# 1140| Type = [IntType] int
7957+
# 1140| ValueCategory = prvalue
7958+
# 1140| 0: [VariableAccess] b
7959+
# 1140| Type = [BoolType] bool
7960+
# 1140| ValueCategory = prvalue(load)
7961+
# 1140| 1: [Literal] 7
7962+
# 1140| Type = [IntType] int
7963+
# 1140| Value = [Literal] 7
7964+
# 1140| ValueCategory = prvalue
7965+
# 1140| 2: [ThrowExpr] throw ...
7966+
# 1140| Type = [Struct] String
7967+
# 1140| ValueCategory = prvalue
7968+
# 1140| 0: [ConstructorCall] call to String
7969+
# 1140| Type = [VoidType] void
7970+
# 1140| ValueCategory = prvalue
7971+
# 1140| 0: [ArrayToPointerConversion] array to pointer conversion
7972+
# 1140| Type = [PointerType] const char *
7973+
# 1140| ValueCategory = prvalue
7974+
# 1140| expr: String object
7975+
# 1140| Type = [ArrayType] const char[14]
7976+
# 1140| Value = [StringLiteral] "String object"
7977+
# 1140| ValueCategory = lvalue
7978+
# 1142| 2: [ExprStmt] ExprStmt
7979+
# 1142| 0: [AssignExpr] ... = ...
7980+
# 1142| Type = [IntType] int
7981+
# 1142| ValueCategory = lvalue
7982+
# 1142| 0: [VariableAccess] x
7983+
# 1142| Type = [IntType] int
7984+
# 1142| ValueCategory = lvalue
7985+
# 1142| 1: [Literal] 7
7986+
# 1142| Type = [IntType] int
7987+
# 1142| Value = [Literal] 7
7988+
# 1142| ValueCategory = prvalue
7989+
# 1144| 1: [Handler] <handler>
7990+
# 1144| 0: [CatchBlock] { ... }
7991+
# 1145| 0: [ExprStmt] ExprStmt
7992+
# 1145| 0: [ThrowExpr] throw ...
7993+
# 1145| Type = [Struct] String
7994+
# 1145| ValueCategory = prvalue
7995+
# 1145| 0: [ConstructorCall] call to String
7996+
# 1145| Type = [VoidType] void
7997+
# 1145| ValueCategory = prvalue
7998+
# 1145| 0: [VariableAccess] s
7999+
# 1145| Type = [PointerType] const char *
8000+
# 1145| ValueCategory = prvalue(load)
8001+
# 1147| 2: [Handler] <handler>
8002+
# 1147| 0: [CatchBlock] { ... }
8003+
# 1149| 1: [ReturnStmt] return ...

0 commit comments

Comments
 (0)