Skip to content

Commit 73d2d9b

Browse files
committed
Python: Make constructor calls post-update nodes
1 parent 9aa0cfb commit 73d2d9b

File tree

11 files changed

+167
-285
lines changed

11 files changed

+167
-285
lines changed

python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,42 @@ class DataFlowCfgNode extends ControlFlowNode {
1616
DataFlowCfgNode() { isExpressionNode(this) }
1717
}
1818

19-
/** A data flow node which should have an associated post-update node. */
20-
abstract class PreUpdateNode extends Node {
19+
/** A data flow node for which we should synthesise an associated pre-update node. */
20+
abstract class NeedsSyntheticPreUpdateNode extends Node {
21+
abstract string label();
22+
}
23+
24+
class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode {
25+
NeedsSyntheticPreUpdateNode post;
26+
27+
SyntheticPreUpdateNode() { this = TSyntheticPreUpdateNode(post) }
28+
29+
/** Gets the node for which this is a synthetic pre-update node. */
30+
Node getPostUpdateNode() { result = post }
31+
32+
override string toString() { result = "[pre " + post.label() + "] " + post.toString() }
33+
34+
override Scope getScope() { result = post.getScope() }
35+
36+
override Location getLocation() { result = post.getLocation() }
37+
}
38+
39+
/** A data flow node for which we should synthesise an associated post-update node. */
40+
abstract class NeedsSyntheticPostUpdateNode extends Node {
2141
abstract string label();
2242
}
2343

2444
/** An argument might have its value changed as a result of a call. */
25-
class ArgumentPreUpdateNode extends PreUpdateNode, ExplicitArgumentNode {
45+
class ArgumentPreUpdateNode extends NeedsSyntheticPostUpdateNode, ArgumentNode {
46+
// Certain arguments, such as implicit self arguments are already post-update nodes
47+
// and should not have an extra node synthesised.
48+
ArgumentPreUpdateNode() { this.isNotPostUpdate() }
49+
2650
override string label() { result = "arg" }
2751
}
2852

2953
/** An object might have its value changed after a store. */
30-
class StorePreUpdateNode extends PreUpdateNode, CfgNode {
54+
class StorePreUpdateNode extends NeedsSyntheticPostUpdateNode, CfgNode {
3155
StorePreUpdateNode() {
3256
exists(Attribute a |
3357
node = a.getObject().getAFlowNode() and
@@ -39,7 +63,7 @@ class StorePreUpdateNode extends PreUpdateNode, CfgNode {
3963
}
4064

4165
/** A node marking the state change of an object after a read. */
42-
class ReadPreUpdateNode extends PreUpdateNode, CfgNode {
66+
class ReadPreUpdateNode extends NeedsSyntheticPostUpdateNode, CfgNode {
4367
ReadPreUpdateNode() {
4468
exists(Attribute a |
4569
node = a.getObject().getAFlowNode() and
@@ -58,16 +82,21 @@ class ReadPreUpdateNode extends PreUpdateNode, CfgNode {
5882
* (which might have mutated the argument), or the qualifier of a field after
5983
* an update to the field.
6084
*
61-
* Nodes corresponding to AST elements, for example `ExprNode`, usually refer
62-
* to the value before the update.
85+
* Nodes corresponding to AST elements, for example `ExprNode`s, usually refer
86+
* to the value before the update with the exception of `ObjectCreationNode`s,
87+
* which represents the value after the constructor has run.
6388
*/
64-
class PostUpdateNode extends Node, TPostUpdateNode {
65-
PreUpdateNode pre;
89+
abstract class PostUpdateNode extends Node {
90+
/** Gets the node before the state update. */
91+
abstract Node getPreUpdateNode();
92+
}
6693

67-
PostUpdateNode() { this = TPostUpdateNode(pre) }
94+
class SyntheticPostUpdateNode extends PostUpdateNode, TSyntheticPostUpdateNode {
95+
NeedsSyntheticPostUpdateNode pre;
6896

69-
/** Gets the node before the state update. */
70-
Node getPreUpdateNode() { result = pre }
97+
SyntheticPostUpdateNode() { this = TSyntheticPostUpdateNode(pre) }
98+
99+
override Node getPreUpdateNode() { result = pre }
71100

72101
override string toString() { result = "[post " + pre.label() + "] " + pre.toString() }
73102

@@ -76,6 +105,14 @@ class PostUpdateNode extends Node, TPostUpdateNode {
76105
override Location getLocation() { result = pre.getLocation() }
77106
}
78107

108+
class ObjectCreationNode extends PostUpdateNode, NeedsSyntheticPreUpdateNode, CfgNode {
109+
ObjectCreationNode() { node.(CallNode) = any(ClassValue c).getACall() }
110+
111+
override Node getPreUpdateNode() { result.(SyntheticPreUpdateNode).getPostUpdateNode() = this }
112+
113+
override string label() { result = "objCreate" }
114+
}
115+
79116
class DataFlowExpr = Expr;
80117

81118
/**
@@ -199,7 +236,7 @@ abstract class DataFlowCall extends TDataFlowCall {
199236
abstract DataFlowCallable getCallable();
200237

201238
/** Get the specified argument to this call. */
202-
abstract ControlFlowNode getArg(int n);
239+
abstract Node getArg(int n);
203240

204241
/** Get the control flow node representing this call. */
205242
abstract ControlFlowNode getNode();
@@ -220,7 +257,7 @@ class CallNodeCall extends DataFlowCall, TCallNode {
220257

221258
override string toString() { result = call.toString() }
222259

223-
override ControlFlowNode getArg(int n) { result = call.getArg(n) }
260+
override Node getArg(int n) { result = TCfgNode(call.getArg(n)) }
224261

225262
override ControlFlowNode getNode() { result = call }
226263

@@ -241,10 +278,10 @@ class ClassCall extends DataFlowCall, TClassCall {
241278

242279
override string toString() { result = call.toString() }
243280

244-
override ControlFlowNode getArg(int n) {
245-
result = call.getArg(n - 1)
281+
override Node getArg(int n) {
282+
n > 0 and result = TCfgNode(call.getArg(n - 1))
246283
or
247-
n = 0 and result = call
284+
n = 0 and result = TSyntheticPreUpdateNode(TCfgNode(call))
248285
}
249286

250287
override ControlFlowNode getNode() { result = call }
@@ -267,7 +304,7 @@ class SpecialCall extends DataFlowCall, TSpecialCall {
267304

268305
override string toString() { result = special.toString() }
269306

270-
override ControlFlowNode getArg(int n) { result = special.(SpecialMethod::Potential).getArg(n) }
307+
override Node getArg(int n) { result = TCfgNode(special.(SpecialMethod::Potential).getArg(n)) }
271308

272309
override ControlFlowNode getNode() { result = special }
273310

@@ -279,23 +316,23 @@ class SpecialCall extends DataFlowCall, TSpecialCall {
279316
}
280317

281318
/** A data flow node that represents a call argument. */
282-
abstract class ArgumentNode extends CfgNode {
283-
/** Holds if this argument occurs at the given position in the given call. */
284-
abstract predicate argumentOf(DataFlowCall call, int pos);
285-
286-
/** Gets the call in which this node is an argument. */
287-
abstract DataFlowCall getCall();
288-
}
289-
290-
/** A data flow node that represents a call argument. */
291-
class ExplicitArgumentNode extends ArgumentNode {
292-
ExplicitArgumentNode() { exists(DataFlowCall call, int pos | node = call.getArg(pos)) }
319+
class ArgumentNode extends Node {
320+
ArgumentNode() { this = any(DataFlowCall c).getArg(_) }
293321

294322
/** Holds if this argument occurs at the given position in the given call. */
295-
override predicate argumentOf(DataFlowCall call, int pos) { node = call.getArg(pos) }
323+
predicate argumentOf(DataFlowCall call, int pos) { this = call.getArg(pos) }
296324

297325
/** Gets the call in which this node is an argument. */
298-
final override DataFlowCall getCall() { this.argumentOf(result, _) }
326+
final DataFlowCall getCall() { this.argumentOf(result, _) }
327+
328+
predicate isNotPostUpdate() {
329+
// Avoid argument 0 of class calls as those have non-synthetic post-update nodes.
330+
exists(CallNodeCall c | this = c.getArg(_))
331+
or
332+
exists(ClassCall c, int n | n > 0 | this = c.getArg(n))
333+
or
334+
exists(SpecialCall c | this = c.getArg(_))
335+
}
299336
}
300337

301338
/** Gets a viable run-time target for the call `call`. */

python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ newtype TNode =
2323
TEssaNode(EssaVariable var) or
2424
/** A node corresponding to a control flow node. */
2525
TCfgNode(DataFlowCfgNode node) or
26-
/** A node representing the value of an object after a state change */
27-
TPostUpdateNode(PreUpdateNode pre)
26+
/** A synthetic node representing the value of an object before a state change */
27+
TSyntheticPreUpdateNode(NeedsSyntheticPreUpdateNode post) or
28+
/** A synthetic node representing the value of an object after a state change */
29+
TSyntheticPostUpdateNode(NeedsSyntheticPostUpdateNode pre)
2830

2931
/**
3032
* An element, viewed as a node in a data flow graph. Either an SSA variable

0 commit comments

Comments
 (0)