Skip to content

Commit c50067b

Browse files
author
Max Schaefer
committed
JavaScript: Refactor type tracking to avoid computing very large relations.
1 parent 084159d commit c50067b

File tree

2 files changed

+46
-60
lines changed

2 files changed

+46
-60
lines changed

javascript/ql/src/semmle/javascript/dataflow/Sources.qll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@ class SourceNode extends DataFlow::Node {
162162
*
163163
* See `TypeTracker` for more details about how to use this.
164164
*/
165-
cached
165+
pragma[inline]
166166
DataFlow::SourceNode track(TypeTracker t2, TypeTracker t) {
167167
exists(StepSummary summary |
168168
StepSummary::step(this, result, summary) and
169-
t = StepSummary::append(t2, summary)
169+
t = t2.append(summary)
170170
)
171171
}
172172

@@ -177,11 +177,11 @@ class SourceNode extends DataFlow::Node {
177177
*
178178
* See `TypeBackTracker` for more details about how to use this.
179179
*/
180-
cached
180+
pragma[inline]
181181
DataFlow::SourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) {
182182
exists(StepSummary summary |
183183
StepSummary::step(result, this, summary) and
184-
t = StepSummary::prepend(summary, t2)
184+
t = t2.prepend(summary)
185185
)
186186
}
187187
}

javascript/ql/src/semmle/javascript/dataflow/TypeTracking.qll

Lines changed: 42 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ private class PropertyName extends string {
1313
PropertyName() { this = any(DataFlow::PropRef pr).getPropertyName() }
1414
}
1515

16+
private class OptionalPropertyName extends string {
17+
OptionalPropertyName() { this instanceof PropertyName or this = "" }
18+
}
19+
1620
/**
1721
* A description of a step on an inter-procedural data flow path.
1822
*/
@@ -29,19 +33,21 @@ private newtype TStepSummary =
2933
* A description of a step on an inter-procedural data flow path.
3034
*/
3135
class StepSummary extends TStepSummary {
32-
/** Indicates whether the step represented by this summary is a return. */
33-
boolean hasReturn() { if this instanceof ReturnStep then result = true else result = false }
34-
35-
/** Indicates whether the step represented by this summary is a call. */
36-
boolean hasCall() { if this instanceof CallStep then result = true else result = false }
37-
3836
/** Gets a textual representation of this step summary. */
3937
string toString() {
4038
this instanceof LevelStep and result = "level"
4139
or
4240
this instanceof CallStep and result = "call"
4341
or
4442
this instanceof ReturnStep and result = "return"
43+
or
44+
exists(string prop | this = StoreStep(prop) |
45+
result = "store " + prop
46+
)
47+
or
48+
exists(string prop | this = LoadStep(prop) |
49+
result = "load" + prop
50+
)
4551
}
4652
}
4753

@@ -80,58 +86,10 @@ module StepSummary {
8086
)
8187
)
8288
}
83-
84-
/**
85-
* INTERNAL. Do not use.
86-
*
87-
* Appends a step summary onto a type-tracking summary.
88-
*/
89-
TypeTracker append(TypeTracker type, StepSummary summary) {
90-
exists(boolean hadCall, boolean hasCall, string oldProp, string newProp |
91-
hadCall = type.hasCall() and
92-
oldProp = type.getProp()
93-
|
94-
not (hadCall = true and summary.hasReturn() = true) and
95-
hasCall = hadCall.booleanOr(summary.hasCall()) and
96-
(
97-
if summary instanceof StoreStep
98-
then oldProp = "" and summary = StoreStep(newProp)
99-
else
100-
if summary instanceof LoadStep
101-
then summary = LoadStep(oldProp) and newProp = ""
102-
else newProp = oldProp
103-
) and
104-
result = MkTypeTracker(hasCall, newProp)
105-
)
106-
}
107-
108-
/**
109-
* INTERNAL. Do not use.
110-
*
111-
* Prepends a step summary before a backwards type-tracking summary.
112-
*/
113-
TypeBackTracker prepend(StepSummary summary, TypeBackTracker type) {
114-
exists(boolean hadReturn, boolean hasReturn, string oldProp, string newProp |
115-
hadReturn = type.hasReturn() and
116-
oldProp = type.getProp()
117-
|
118-
not (hadReturn = true and summary.hasCall() = true) and
119-
hasReturn = hadReturn.booleanOr(summary.hasReturn()) and
120-
(
121-
if summary instanceof StoreStep
122-
then summary = StoreStep(oldProp) and newProp = ""
123-
else
124-
if summary instanceof LoadStep
125-
then oldProp = "" and summary = LoadStep(newProp)
126-
else newProp = oldProp
127-
) and
128-
result = MkTypeBackTracker(hasReturn, newProp)
129-
)
130-
}
13189
}
13290

13391
private newtype TTypeTracker =
134-
MkTypeTracker(Boolean hasCall, string prop) { prop = "" or prop instanceof PropertyName }
92+
MkTypeTracker(Boolean hasCall, OptionalPropertyName prop)
13593

13694
/**
13795
* EXPERIMENTAL.
@@ -168,6 +126,20 @@ class TypeTracker extends TTypeTracker {
168126

169127
TypeTracker() { this = MkTypeTracker(hasCall, prop) }
170128

129+
TypeTracker append(StepSummary step) {
130+
step = LevelStep() and result = this
131+
or
132+
step = CallStep() and result = MkTypeTracker(true, prop)
133+
or
134+
step = ReturnStep() and hasCall = false and result = this
135+
or
136+
step = LoadStep(prop) and result = MkTypeTracker(hasCall, "")
137+
or
138+
exists(string p |
139+
step = StoreStep(p) and prop = "" and result = MkTypeTracker(hasCall, p)
140+
)
141+
}
142+
171143
string toString() {
172144
exists(string withCall, string withProp |
173145
(if hasCall = true then withCall = "with" else withCall = "without") and
@@ -198,7 +170,7 @@ module TypeTracker {
198170
}
199171

200172
private newtype TTypeBackTracker =
201-
MkTypeBackTracker(Boolean hasReturn, string prop) { prop = "" or prop instanceof PropertyName }
173+
MkTypeBackTracker(Boolean hasReturn, OptionalPropertyName prop)
202174

203175
/**
204176
* EXPERIMENTAL.
@@ -234,6 +206,20 @@ class TypeBackTracker extends TTypeBackTracker {
234206

235207
TypeBackTracker() { this = MkTypeBackTracker(hasReturn, prop) }
236208

209+
TypeBackTracker prepend(StepSummary step) {
210+
step = LevelStep() and result = this
211+
or
212+
step = CallStep() and hasReturn = false and result = this
213+
or
214+
step = ReturnStep() and result = MkTypeBackTracker(true, prop)
215+
or
216+
exists(string p |
217+
step = LoadStep(p) and prop = "" and result = MkTypeBackTracker(hasReturn, p)
218+
)
219+
or
220+
step = StoreStep(prop) and result = MkTypeBackTracker(hasReturn, "")
221+
}
222+
237223
string toString() {
238224
exists(string withReturn, string withProp |
239225
(if hasReturn = true then withReturn = "with" else withReturn = "without") and

0 commit comments

Comments
 (0)