|
80 | 80 | */ |
81 | 81 |
|
82 | 82 | private import cpp |
83 | | -private import semmle.code.cpp.controlflow.internal.SyntheticDestructorCalls |
84 | 83 |
|
85 | 84 | /** |
86 | 85 | * A control-flow node. This class exists to provide a shorter name than |
@@ -115,8 +114,7 @@ private class Node extends ControlFlowNodeBase { |
115 | 114 | */ |
116 | 115 | private predicate excludeNodeAndNodesBelow(Expr e) { |
117 | 116 | 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 |
120 | 118 | or |
121 | 119 | // Constructor init lists should be evaluated, and we can change this in |
122 | 120 | // 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) |
983 | 981 | // called, connect the "before destructors" node directly to the "after |
984 | 982 | // destructors" node. For performance, only do this when the nodes exist. |
985 | 983 | exists(Pos afterDtors | afterDtors.isAfterDestructors() | subEdge(afterDtors, n1, _, _)) and |
986 | | - not exists(getDestructorCallAfterNode(n1, 0)) and |
| 984 | + not exists(getSynthesisedDestructorCallAfterNode(n1, 0)) and |
987 | 985 | p1.nodeBeforeDestructors(n1, n1) and |
988 | 986 | p2.nodeAfterDestructors(n2, n1) |
989 | 987 | or |
990 | 988 | 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())) |
1000 | 994 | or |
1001 | | - // call(i) -> access(i+1) |
| 995 | + // call(i+1) -> access(i) |
1002 | 996 | 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()) |
1005 | 999 | ) |
1006 | 1000 | 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) |
1013 | 1004 | ) |
1014 | 1005 | } |
1015 | 1006 |
|
| 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 | + |
1016 | 1043 | /** |
1017 | 1044 | * An expression whose outgoing true/false sub-edges may come from different |
1018 | 1045 | * sub-nodes. |
|
0 commit comments