Skip to content

Commit 2622df0

Browse files
authored
Merge pull request #1411 from ian-semmle/qlcfg3
C++: QL CFG: Use synthetic_destructor_call table rather than SyntheticDestructorCalls
2 parents ab507aa + 46cce36 commit 2622df0

File tree

9 files changed

+12807
-9732
lines changed

9 files changed

+12807
-9732
lines changed

cpp/ql/src/semmle/code/cpp/controlflow/internal/CFG.qll

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@
8080
*/
8181

8282
private import cpp
83-
private import semmle.code.cpp.controlflow.internal.SyntheticDestructorCalls
8483

8584
/**
8685
* A control-flow node. This class exists to provide a shorter name than
@@ -115,8 +114,7 @@ private class Node extends ControlFlowNodeBase {
115114
*/
116115
private predicate excludeNodeAndNodesBelow(Expr e) {
117116
not exists(e.getParent()) and
118-
not e instanceof DestructorCall and
119-
not e instanceof SyntheticDestructorCall // Workaround for CPP-320
117+
not e instanceof DestructorCall
120118
or
121119
// Constructor init lists should be evaluated, and we can change this in
122120
// the future, but it would mean that a `Function` entry point is not
@@ -983,36 +981,65 @@ private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2)
983981
// called, connect the "before destructors" node directly to the "after
984982
// destructors" node. For performance, only do this when the nodes exist.
985983
exists(Pos afterDtors | afterDtors.isAfterDestructors() | subEdge(afterDtors, n1, _, _)) and
986-
not exists(getDestructorCallAfterNode(n1, 0)) and
984+
not exists(getSynthesisedDestructorCallAfterNode(n1, 0)) and
987985
p1.nodeBeforeDestructors(n1, n1) and
988986
p2.nodeAfterDestructors(n2, n1)
989987
or
990988
exists(Node n |
991-
// before destructors -> access(0)
992-
p1.nodeBeforeDestructors(n1, n) and
993-
p2.nodeAt(n2, getDestructorCallAfterNode(n, 0).getAccess())
994-
or
995-
// access(i) -> call(i)
996-
exists(int i |
997-
p1.nodeAt(n1, getDestructorCallAfterNode(n, i).getAccess()) and
998-
p2.nodeAt(n2, getDestructorCallAfterNode(n, i))
999-
)
989+
// before destructors -> access(max)
990+
exists(int maxCallIndex |
991+
maxCallIndex = max(int i | exists(getSynthesisedDestructorCallAfterNode(n, i))) and
992+
p1.nodeBeforeDestructors(n1, n) and
993+
p2.nodeAt(n2, getSynthesisedDestructorCallAfterNode(n, maxCallIndex).getQualifier()))
1000994
or
1001-
// call(i) -> access(i+1)
995+
// call(i+1) -> access(i)
1002996
exists(int i |
1003-
p1.nodeAt(n1, getDestructorCallAfterNode(n, i)) and
1004-
p2.nodeAt(n2, getDestructorCallAfterNode(n, i + 1).getAccess())
997+
p1.nodeAt(n1, getSynthesisedDestructorCallAfterNode(n, i + 1)) and
998+
p2.nodeAt(n2, getSynthesisedDestructorCallAfterNode(n, i).getQualifier())
1005999
)
10061000
or
1007-
// call(max) -> after destructors end
1008-
exists(int maxCallIndex |
1009-
maxCallIndex = max(int i | exists(getDestructorCallAfterNode(n, i))) and
1010-
p1.nodeAt(n1, getDestructorCallAfterNode(n, maxCallIndex)) and
1011-
p2.nodeAfterDestructors(n2, n)
1012-
)
1001+
// call(0) -> after destructors end
1002+
p1.nodeAt(n1, getSynthesisedDestructorCallAfterNode(n, 0)) and
1003+
p2.nodeAfterDestructors(n2, n)
10131004
)
10141005
}
10151006

1007+
/**
1008+
* Gets the synthetic constructor call for the `index`'th entity that
1009+
* should be destructed following `node`. Note that entities should be
1010+
* destructed in reverse construction order, so these should be called
1011+
* from highest to lowest index.
1012+
*
1013+
* The exact placement of that call in the CFG depends on the type of
1014+
* `node` as follows:
1015+
*
1016+
* - `Block`: after ordinary control flow falls off the end of the block
1017+
* without jumps or exceptions.
1018+
* - `ReturnStmt`: After the statement itself or after its operand (if
1019+
* present).
1020+
* - `ThrowExpr`: After the `throw` expression or after its operand (if
1021+
* present).
1022+
* - `JumpStmt` (`BreakStmt`, `ContinueStmt`, `GotoStmt`): after the statement.
1023+
* - A `ForStmt`, `WhileStmt`, `SwitchStmt`, or `IfStmt`: after control flow
1024+
* falls off the end of the statement without jumping. Destruction can occur
1025+
* here for `for`-loops that have an initializer (`for (C x = a; ...; ...)`)
1026+
* and for statements whose condition is a `ConditionDeclExpr`
1027+
* (`if (C x = a)`).
1028+
* - The `getUpdate()` of a `ForStmt`: after the `getUpdate()` expression. This
1029+
* can happen when the condition is a `ConditionDeclExpr`
1030+
* - `Handler`: On the edge out of the `Handler` for the case where the
1031+
* exception was not matched and is propagated to the next handler or
1032+
* function exit point.
1033+
* - `MicrosoftTryExceptStmt`: After the false-edge out of the `e` in
1034+
* `__except(e)`, before propagating the exception up to the next handler or
1035+
* function exit point.
1036+
* - `MicrosoftTryFinallyStmt`: On the edge following the `__finally` block for
1037+
* the case where an exception was thrown and needs to be propagated.
1038+
*/
1039+
DestructorCall getSynthesisedDestructorCallAfterNode(Node n, int i) {
1040+
synthetic_destructor_call(n, i, result)
1041+
}
1042+
10161043
/**
10171044
* An expression whose outgoing true/false sub-edges may come from different
10181045
* sub-nodes.

cpp/ql/src/semmle/code/cpp/controlflow/internal/SyntheticDestructorCalls.qll

Lines changed: 0 additions & 247 deletions
This file was deleted.

cpp/ql/src/semmlecode.cpp.dbscheme

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,17 +181,24 @@ tokens(
181181
int endColumn : int ref
182182
);
183183

184-
/*
185-
* Mapping of header files to packages
184+
/**
185+
* Information about packages that provide code used during compilation.
186+
* The `id` is just a unique identifier.
187+
* The `namespace` is typically the name of the package manager that
188+
* provided the package (e.g. "dpkg" or "yum").
189+
* The `package_name` is the name of the package, and `version` is its
190+
* version (as a string).
186191
*/
187-
188192
external_packages(
189193
unique int id: @external_package,
190-
string namespace : string ref, // "dpkg", "yum", ...
194+
string namespace : string ref,
191195
string package_name : string ref,
192196
string version : string ref
193197
);
194198

199+
/**
200+
* Holds if File `fileid` was provided by package `package`.
201+
*/
195202
header_to_external_package(
196203
int fileid : @file ref,
197204
int package : @external_package ref
@@ -1041,6 +1048,17 @@ exprconv(
10411048

10421049
compgenerated(unique int id: @element ref);
10431050

1051+
/**
1052+
* `destructor_call` destructs the `i`'th entity that should be
1053+
* destructed following `element`. Note that entities should be
1054+
* destructed in reverse construction order, so for a given `element`
1055+
* these should be called from highest to lowest `i`.
1056+
*/
1057+
synthetic_destructor_call(
1058+
int element: @element ref,
1059+
int i: int ref,
1060+
unique int destructor_call: @routineexpr ref
1061+
);
10441062

10451063
namespaces(
10461064
unique int id: @namespace,

0 commit comments

Comments
 (0)