Skip to content

Commit 4dfd4f1

Browse files
authored
Merge pull request #1674 from dave-bartolomeo/dave/ExternDecls2
C++: Two IR fixes and a PrintAST workaround
2 parents 77eac2c + 6370391 commit 4dfd4f1

File tree

15 files changed

+514
-61
lines changed

15 files changed

+514
-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/aliased_ssa/Instruction.qll

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,55 @@ module InstructionSanity {
215215
) and
216216
fromInstr != fromBlock
217217
}
218+
219+
/**
220+
* Gets the point in the function at which the specified operand is evaluated. For most operands,
221+
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
222+
* of evaluation is at the end of the corresponding predecessor block.
223+
*/
224+
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
225+
(
226+
block = operand.(PhiInputOperand).getPredecessorBlock() and
227+
index = block.getInstructionCount()
228+
) or
229+
exists (Instruction use |
230+
use = operand.(NonPhiOperand).getUse() and
231+
block.getInstruction(index) = use
232+
)
233+
}
234+
235+
/**
236+
* Holds if `useOperand` has a definition that does not dominate the use.
237+
*/
238+
query predicate useNotDominatedByDefinition(Operand useOperand, string message, IRFunction func,
239+
string funcText) {
240+
241+
exists (IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
242+
not useOperand.getUse() instanceof UnmodeledUseInstruction and
243+
pointOfEvaluation(useOperand, useBlock, useIndex) and
244+
defInstr = useOperand.getAnyDef() and
245+
(
246+
(
247+
defInstr instanceof PhiInstruction and
248+
defBlock = defInstr.getBlock() and
249+
defIndex = -1
250+
)
251+
or
252+
defBlock.getInstruction(defIndex) = defInstr
253+
) and
254+
not (
255+
defBlock.strictlyDominates(useBlock) or
256+
(
257+
defBlock = useBlock and
258+
defIndex < useIndex
259+
)
260+
) and
261+
message = "Operand '" + useOperand.toString() +
262+
"' is not dominated by its definition in function '$@'." and
263+
func = useOperand.getEnclosingIRFunction() and
264+
funcText = Language::getIdentityString(func.getFunction())
265+
)
266+
}
218267
}
219268

220269
/**

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,55 @@ module InstructionSanity {
215215
) and
216216
fromInstr != fromBlock
217217
}
218+
219+
/**
220+
* Gets the point in the function at which the specified operand is evaluated. For most operands,
221+
* this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
222+
* of evaluation is at the end of the corresponding predecessor block.
223+
*/
224+
private predicate pointOfEvaluation(Operand operand, IRBlock block, int index) {
225+
(
226+
block = operand.(PhiInputOperand).getPredecessorBlock() and
227+
index = block.getInstructionCount()
228+
) or
229+
exists (Instruction use |
230+
use = operand.(NonPhiOperand).getUse() and
231+
block.getInstruction(index) = use
232+
)
233+
}
234+
235+
/**
236+
* Holds if `useOperand` has a definition that does not dominate the use.
237+
*/
238+
query predicate useNotDominatedByDefinition(Operand useOperand, string message, IRFunction func,
239+
string funcText) {
240+
241+
exists (IRBlock useBlock, int useIndex, Instruction defInstr, IRBlock defBlock, int defIndex |
242+
not useOperand.getUse() instanceof UnmodeledUseInstruction and
243+
pointOfEvaluation(useOperand, useBlock, useIndex) and
244+
defInstr = useOperand.getAnyDef() and
245+
(
246+
(
247+
defInstr instanceof PhiInstruction and
248+
defBlock = defInstr.getBlock() and
249+
defIndex = -1
250+
)
251+
or
252+
defBlock.getInstruction(defIndex) = defInstr
253+
) and
254+
not (
255+
defBlock.strictlyDominates(useBlock) or
256+
(
257+
defBlock = useBlock and
258+
defIndex < useIndex
259+
)
260+
) and
261+
message = "Operand '" + useOperand.toString() +
262+
"' is not dominated by its definition in function '$@'." and
263+
func = useOperand.getEnclosingIRFunction() and
264+
funcText = Language::getIdentityString(func.getFunction())
265+
)
266+
}
218267
}
219268

220269
/**

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
}

0 commit comments

Comments
 (0)