|
8 | 8 |
|
9 | 9 | private import javascript |
10 | 10 | private import internal.FlowSteps |
11 | | - |
12 | | -private class PropertyName extends string { |
13 | | - PropertyName() { |
14 | | - this = any(DataFlow::PropRef pr).getPropertyName() |
15 | | - or |
16 | | - AccessPath::isAssignedInUniqueFile(this) |
17 | | - or |
18 | | - exists(AccessPath::getAnAssignmentTo(_, this)) |
19 | | - or |
20 | | - this instanceof TypeTrackingPseudoProperty |
21 | | - } |
22 | | -} |
23 | | - |
24 | | -/** |
25 | | - * A pseudo-property that can be used in type-tracking. |
26 | | - */ |
27 | | -abstract class TypeTrackingPseudoProperty extends string { |
28 | | - bindingset[this] |
29 | | - TypeTrackingPseudoProperty() { any() } |
30 | | -} |
31 | | - |
32 | | -private class OptionalPropertyName extends string { |
33 | | - OptionalPropertyName() { this instanceof PropertyName or this = "" } |
34 | | -} |
35 | | - |
36 | | -/** |
37 | | - * A description of a step on an inter-procedural data flow path. |
38 | | - */ |
39 | | -newtype TStepSummary = |
40 | | - LevelStep() or |
41 | | - CallStep() or |
42 | | - ReturnStep() or |
43 | | - StoreStep(PropertyName prop) or |
44 | | - LoadStep(PropertyName prop) |
45 | | - |
46 | | -/** |
47 | | - * INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead. |
48 | | - * |
49 | | - * A description of a step on an inter-procedural data flow path. |
50 | | - */ |
51 | | -class StepSummary extends TStepSummary { |
52 | | - /** Gets a textual representation of this step summary. */ |
53 | | - string toString() { |
54 | | - this instanceof LevelStep and result = "level" |
55 | | - or |
56 | | - this instanceof CallStep and result = "call" |
57 | | - or |
58 | | - this instanceof ReturnStep and result = "return" |
59 | | - or |
60 | | - exists(string prop | this = StoreStep(prop) | result = "store " + prop) |
61 | | - or |
62 | | - exists(string prop | this = LoadStep(prop) | result = "load " + prop) |
63 | | - } |
64 | | -} |
65 | | - |
66 | | -module StepSummary { |
67 | | - /** |
68 | | - * INTERNAL: Use `SourceNode.track()` or `SourceNode.backtrack()` instead. |
69 | | - */ |
70 | | - cached |
71 | | - predicate step(DataFlow::SourceNode pred, DataFlow::SourceNode succ, StepSummary summary) { |
72 | | - exists(DataFlow::Node mid | pred.flowsTo(mid) | smallstep(mid, succ, summary)) |
73 | | - } |
74 | | - |
75 | | - /** |
76 | | - * INTERNAL: Use `TypeBackTracker.smallstep()` instead. |
77 | | - */ |
78 | | - predicate smallstep(DataFlow::Node pred, DataFlow::Node succ, StepSummary summary) { |
79 | | - // Flow through properties of objects |
80 | | - propertyFlowStep(pred, succ) and |
81 | | - summary = LevelStep() |
82 | | - or |
83 | | - // Flow through global variables |
84 | | - globalFlowStep(pred, succ) and |
85 | | - summary = LevelStep() |
86 | | - or |
87 | | - // Flow into function |
88 | | - callStep(pred, succ) and |
89 | | - summary = CallStep() |
90 | | - or |
91 | | - // Flow out of function |
92 | | - returnStep(pred, succ) and |
93 | | - summary = ReturnStep() |
94 | | - or |
95 | | - // Flow through an instance field between members of the same class |
96 | | - DataFlow::localFieldStep(pred, succ) and |
97 | | - summary = LevelStep() |
98 | | - or |
99 | | - exists(string prop | |
100 | | - basicStoreStep(pred, succ, prop) and |
101 | | - summary = StoreStep(prop) |
102 | | - or |
103 | | - basicLoadStep(pred, succ, prop) and |
104 | | - summary = LoadStep(prop) |
105 | | - ) |
106 | | - or |
107 | | - any(AdditionalTypeTrackingStep st).step(pred, succ) and |
108 | | - summary = LevelStep() |
109 | | - or |
110 | | - // Store to global access path |
111 | | - exists(string name | |
112 | | - pred = AccessPath::getAnAssignmentTo(name) and |
113 | | - AccessPath::isAssignedInUniqueFile(name) and |
114 | | - succ = DataFlow::globalAccessPathRootPseudoNode() and |
115 | | - summary = StoreStep(name) |
116 | | - ) |
117 | | - or |
118 | | - // Load from global access path |
119 | | - exists(string name | |
120 | | - succ = AccessPath::getAReferenceTo(name) and |
121 | | - AccessPath::isAssignedInUniqueFile(name) and |
122 | | - pred = DataFlow::globalAccessPathRootPseudoNode() and |
123 | | - summary = LoadStep(name) |
124 | | - ) |
125 | | - or |
126 | | - // Store to non-global access path |
127 | | - exists(string name | |
128 | | - pred = AccessPath::getAnAssignmentTo(succ, name) and |
129 | | - summary = StoreStep(name) |
130 | | - ) |
131 | | - or |
132 | | - // Load from non-global access path |
133 | | - exists(string name | |
134 | | - succ = AccessPath::getAReferenceTo(pred, name) and |
135 | | - summary = LoadStep(name) and |
136 | | - name != "" |
137 | | - ) |
138 | | - or |
139 | | - // Step in/out of a promise |
140 | | - succ = PromiseTypeTracking::promiseStep(pred, summary) |
141 | | - or |
142 | | - // Summarize calls with flow directly from a parameter to a return. |
143 | | - exists(DataFlow::ParameterNode param, DataFlow::FunctionNode fun | |
144 | | - ( |
145 | | - param.flowsTo(fun.getAReturn()) and |
146 | | - summary = LevelStep() |
147 | | - or |
148 | | - exists(string prop | |
149 | | - param.getAPropertyRead(prop).flowsTo(fun.getAReturn()) and |
150 | | - summary = LoadStep(prop) |
151 | | - ) |
152 | | - ) and |
153 | | - if param = fun.getAParameter() |
154 | | - then |
155 | | - // Step from argument to call site. |
156 | | - argumentPassing(succ, pred, fun.getFunction(), param) |
157 | | - else ( |
158 | | - // Step from captured parameter to local call sites |
159 | | - pred = param and |
160 | | - succ = fun.getAnInvocation() |
161 | | - ) |
162 | | - ) |
163 | | - } |
164 | | -} |
| 11 | +private import internal.StepSummary |
165 | 12 |
|
166 | 13 | private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalPropertyName prop) |
167 | 14 |
|
|
0 commit comments