Skip to content

Commit e08fc08

Browse files
committed
don't use pseudo-properties for resolved promise data-flow
1 parent 830100d commit e08fc08

1 file changed

Lines changed: 28 additions & 56 deletions

File tree

javascript/ql/src/semmle/javascript/Promises.qll

Lines changed: 28 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,9 @@ class AggregateES2015PromiseDefinition extends PromiseCreationCall {
121121
}
122122

123123
/**
124-
* This module defines how data-flow propagates into and out a Promise.
124+
* This module defines how exceptional data-flow propagates into and out a Promise.
125125
*/
126-
private module PromiseFlow {
127-
/**
128-
* Gets the pseudo-field used to describe resolved values in a promise.
129-
*/
130-
string resolveField() {
131-
result = "$PromiseResolveField$"
132-
}
133-
126+
private module ExceptionalPromiseFlow {
134127
/**
135128
* Gets the pseudo-field used to describe rejected values in a promise.
136129
*/
@@ -141,7 +134,7 @@ private module PromiseFlow {
141134
/**
142135
* A flow step describing a promise definition.
143136
*
144-
* The resolved/rejected value is written to a pseudo-field on the promise.
137+
* The rejected value is written to a pseudo-field on the promise.
145138
*/
146139
class PromiseDefitionStep extends DataFlow::AdditionalFlowStep {
147140
PromiseDefinition promise;
@@ -150,10 +143,6 @@ private module PromiseFlow {
150143
}
151144

152145
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
153-
prop = resolveField() and
154-
pred = promise.getResolveParameter().getACall().getArgument(0) and
155-
succ = this
156-
or
157146
prop = rejectField() and
158147
(
159148
pred = promise.getRejectParameter().getACall().getArgument(0) or
@@ -164,25 +153,8 @@ private module PromiseFlow {
164153
}
165154

166155
/**
167-
* A flow step describing the a Promise.resolve (and similar) call.
168-
*/
169-
class CreationStep extends DataFlow::AdditionalFlowStep {
170-
PromiseCreationCall promise;
171-
CreationStep() {
172-
this = promise
173-
}
174-
175-
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
176-
prop = resolveField() and
177-
pred = promise.getValue() and
178-
succ = this
179-
}
180-
}
181-
182-
/**
183-
* A load step loading the pseudo-field describing that the promise is either resolved or rejected.
184-
* A resolved value is forwarding as the resulting value of the `await` expression,
185-
* and a rejected value is thrown as a exception.
156+
* A load step loading the pseudo-field describing that the promise is rejected.
157+
* The rejected value is thrown as a exception.
186158
*/
187159
class AwaitStep extends DataFlow::AdditionalFlowStep {
188160
DataFlow::Node operand;
@@ -193,10 +165,6 @@ private module PromiseFlow {
193165
}
194166

195167
override predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) {
196-
prop = resolveField() and
197-
succ = this and
198-
pred = operand.getALocalSource()
199-
or
200168
prop = rejectField() and
201169
succ = await.getExceptionTarget() and
202170
pred = operand.getALocalSource()
@@ -212,10 +180,6 @@ private module PromiseFlow {
212180
}
213181

214182
override predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) {
215-
prop = resolveField() and
216-
pred = getReceiver().getALocalSource() and
217-
succ = getCallback(0).getParameter(0)
218-
or
219183
prop = rejectField() and
220184
pred = getReceiver().getALocalSource() and
221185
succ = getCallback(1).getParameter(0)
@@ -229,10 +193,6 @@ private module PromiseFlow {
229193
}
230194

231195
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
232-
prop = resolveField() and
233-
pred = getCallback([0..1]).getAReturn() and
234-
succ = this
235-
or
236196
prop = rejectField() and
237197
pred = getCallback([0..1]).getExceptionalReturn() and
238198
succ = this
@@ -253,12 +213,6 @@ private module PromiseFlow {
253213
succ = getCallback(0).getParameter(0)
254214
}
255215

256-
override predicate copyProperty(DataFlow::Node pred, DataFlow::Node succ, string prop) {
257-
prop = resolveField() and
258-
pred = getReceiver().getALocalSource() and
259-
succ = this
260-
}
261-
262216
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
263217
prop = rejectField() and
264218
pred = getCallback([0..1]).getExceptionalReturn() and
@@ -275,7 +229,7 @@ private module PromiseFlow {
275229
}
276230

277231
override predicate copyProperty(DataFlow::Node pred, DataFlow::Node succ, string prop) {
278-
(prop = resolveField() or prop = rejectField()) and
232+
prop = rejectField() and
279233
pred = getReceiver().getALocalSource() and
280234
succ = this
281235
}
@@ -292,17 +246,35 @@ predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
292246
// from `x` to `Promise.resolve(x)`
293247
pred = succ.(PromiseCreationCall).getValue()
294248
or
295-
exists(DataFlow::MethodCallNode thn, DataFlow::FunctionNode cb |
296-
thn.getMethodName() = "then" and cb = thn.getCallback(0)
249+
exists(DataFlow::MethodCallNode thn |
250+
thn.getMethodName() = "then"
297251
|
298252
// from `p` to `x` in `p.then(x => ...)`
299253
pred = thn.getReceiver() and
300-
succ = cb.getParameter(0)
254+
succ = thn.getCallback(0).getParameter(0)
301255
or
302256
// from `v` to `p.then(x => return v)`
303-
pred = cb.getAReturn() and
257+
pred = thn.getCallback([0..1]).getAReturn() and
304258
succ = thn
305259
)
260+
or
261+
// from `p` to `p.catch(..)`
262+
exists(DataFlow::MethodCallNode catch | catch.getMethodName() = "catch" |
263+
pred = catch.getReceiver() and
264+
succ = catch
265+
)
266+
or
267+
// from `p` to `p.finally(..)`
268+
exists(DataFlow::MethodCallNode finally | finally.getMethodName() = "finally" |
269+
pred = finally.getReceiver() and
270+
succ = finally
271+
)
272+
or
273+
// from `x` to `await x`
274+
exists(AwaitExpr await |
275+
pred.getEnclosingExpr() = await.getOperand() and
276+
succ.getEnclosingExpr() = await
277+
)
306278
}
307279

308280
/**

0 commit comments

Comments
 (0)