Skip to content

Commit 8370699

Browse files
committed
add support for creating a promise with another resolved promise, e.g: Promise.resolve(otherPromise)
1 parent 8679132 commit 8370699

4 files changed

Lines changed: 47 additions & 3 deletions

File tree

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,13 @@ private module PromiseFlow {
162162
) and
163163
succ = this
164164
}
165+
166+
override predicate copyProperty(DataFlow::Node pred, DataFlow::Node succ, string prop) {
167+
// Copy the value of a resolved promise to the value of this promise.
168+
prop = resolveField() and
169+
pred = promise.getResolveParameter().getACall().getArgument(0) and
170+
succ = this
171+
}
165172
}
166173

167174
/**
@@ -178,6 +185,13 @@ private module PromiseFlow {
178185
pred = promise.getValue() and
179186
succ = this
180187
}
188+
189+
override predicate copyProperty(DataFlow::Node pred, DataFlow::Node succ, string prop) {
190+
// Copy the value of a resolved promise to the value of this promise.
191+
prop = resolveField() and
192+
pred = promise.getValue() and
193+
succ = this
194+
}
181195
}
182196

183197

javascript/ql/test/library-tests/Promises/flow.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,8 @@
125125
Promise.resolve(123).then(x => rejected).catch(x => sink(x)) // NOT OK
126126

127127
Promise.resolve(123).then(x => rejected).then(x => sink(x)) // OK
128+
129+
new Promise((resolve, reject) => resolve(resolved)).then(x => sink(x)); // NOT OK
130+
131+
Promise.resolve(resolved).then(x => sink(x)); // NOT OK
128132
})();

javascript/ql/test/library-tests/Promises/flow.qll

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
import javascript
22

3-
class Configuration extends TaintTracking::Configuration {
4-
Configuration() { this = "PromiseFlowTestingConfig" }
3+
class Configuration extends DataFlow::Configuration {
4+
Configuration() { this = "PromiseDataFlowFlowTestingConfig" }
5+
6+
override predicate isSource(DataFlow::Node source) {
7+
source.getEnclosingExpr().getStringValue() = "source"
8+
}
9+
10+
override predicate isSink(DataFlow::Node sink) {
11+
any(DataFlow::InvokeNode call | call.getCalleeName() = "sink").getAnArgument() = sink
12+
}
13+
}
14+
15+
class TaintConfig extends TaintTracking::Configuration {
16+
TaintConfig() { this = "PromiseTaintFlowTestingConfig" }
517

618
override predicate isSource(DataFlow::Node source) {
719
source.getEnclosingExpr().getStringValue() = "source"
@@ -13,5 +25,10 @@ class Configuration extends TaintTracking::Configuration {
1325
}
1426

1527
query predicate flow(DataFlow::Node source, DataFlow::Node sink) {
16-
any(Configuration a).hasFlow(source, sink)
28+
any(Configuration c).hasFlow(source, sink)
1729
}
30+
31+
query predicate exclusiveTaintFlow(DataFlow::Node source, DataFlow::Node sink) {
32+
not any(Configuration c).hasFlow(source, sink) and
33+
any(TaintConfig c).hasFlow(source, sink)
34+
}

javascript/ql/test/library-tests/Promises/tests.expected

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ test_ResolvedPromiseDefinition
1515
| flow.js:123:2:123:21 | Promise.resolve(123) | flow.js:123:18:123:20 | 123 |
1616
| flow.js:125:2:125:21 | Promise.resolve(123) | flow.js:125:18:125:20 | 123 |
1717
| flow.js:127:2:127:21 | Promise.resolve(123) | flow.js:127:18:127:20 | 123 |
18+
| flow.js:131:2:131:26 | Promise ... solved) | flow.js:131:18:131:25 | resolved |
1819
| promises.js:53:19:53:41 | Promise ... source) | promises.js:53:35:53:40 | source |
1920
| promises.js:62:19:62:41 | Promise ... source) | promises.js:62:35:62:40 | source |
2021
| promises.js:71:5:71:27 | Promise ... source) | promises.js:71:21:71:26 | source |
@@ -58,6 +59,7 @@ test_PromiseDefinition_getExecutor
5859
| flow.js:113:2:113:48 | new Pro ... "BLA")) | flow.js:113:14:113:47 | (resolv ... ("BLA") |
5960
| flow.js:117:2:117:48 | new Pro ... "BLA")) | flow.js:117:14:117:47 | (resolv ... ("BLA") |
6061
| flow.js:119:2:119:48 | new Pro ... "BLA")) | flow.js:119:14:119:47 | (resolv ... ("BLA") |
62+
| flow.js:129:2:129:52 | new Pro ... olved)) | flow.js:129:14:129:51 | (resolv ... solved) |
6163
| interflow.js:11:12:15:6 | new Pro ... \\n }) | interflow.js:11:24:15:5 | functio ... ;\\n } |
6264
| promises.js:3:17:5:4 | new Pro ... );\\n }) | promises.js:3:29:5:3 | functio ... e);\\n } |
6365
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:10:30:17:3 | (res, r ... e);\\n } |
@@ -92,6 +94,7 @@ test_PromiseDefinition
9294
| flow.js:113:2:113:48 | new Pro ... "BLA")) |
9395
| flow.js:117:2:117:48 | new Pro ... "BLA")) |
9496
| flow.js:119:2:119:48 | new Pro ... "BLA")) |
97+
| flow.js:129:2:129:52 | new Pro ... olved)) |
9598
| interflow.js:11:12:15:6 | new Pro ... \\n }) |
9699
| promises.js:3:17:5:4 | new Pro ... );\\n }) |
97100
| promises.js:10:18:17:4 | new Pro ... );\\n }) |
@@ -108,6 +111,7 @@ test_PromiseDefinition_getAResolveHandler
108111
| flow.js:91:21:91:68 | new Pro ... ource)) | flow.js:91:75:91:82 | () => {} |
109112
| flow.js:105:2:105:48 | new Pro ... "BLA")) | flow.js:105:58:105:76 | x => {throw source} |
110113
| flow.js:109:2:109:48 | new Pro ... "BLA")) | flow.js:109:58:109:70 | x => rejected |
114+
| flow.js:129:2:129:52 | new Pro ... olved)) | flow.js:129:59:129:70 | x => sink(x) |
111115
| promises.js:3:17:5:4 | new Pro ... );\\n }) | promises.js:6:16:8:3 | functio ... al;\\n } |
112116
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:18:17:20:3 | (v) => ... v;\\n } |
113117
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:26:20:28:3 | (v) => ... v;\\n } |
@@ -137,6 +141,7 @@ test_PromiseDefinition_getRejectParameter
137141
| flow.js:113:2:113:48 | new Pro ... "BLA")) | flow.js:113:24:113:29 | reject |
138142
| flow.js:117:2:117:48 | new Pro ... "BLA")) | flow.js:117:24:117:29 | reject |
139143
| flow.js:119:2:119:48 | new Pro ... "BLA")) | flow.js:119:24:119:29 | reject |
144+
| flow.js:129:2:129:52 | new Pro ... olved)) | flow.js:129:24:129:29 | reject |
140145
| interflow.js:11:12:15:6 | new Pro ... \\n }) | interflow.js:11:43:11:48 | reject |
141146
| promises.js:3:17:5:4 | new Pro ... );\\n }) | promises.js:3:48:3:53 | reject |
142147
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:10:36:10:38 | rej |
@@ -166,6 +171,7 @@ test_PromiseDefinition_getResolveParameter
166171
| flow.js:113:2:113:48 | new Pro ... "BLA")) | flow.js:113:15:113:21 | resolve |
167172
| flow.js:117:2:117:48 | new Pro ... "BLA")) | flow.js:117:15:117:21 | resolve |
168173
| flow.js:119:2:119:48 | new Pro ... "BLA")) | flow.js:119:15:119:21 | resolve |
174+
| flow.js:129:2:129:52 | new Pro ... olved)) | flow.js:129:15:129:21 | resolve |
169175
| interflow.js:11:12:15:6 | new Pro ... \\n }) | interflow.js:11:34:11:40 | resolve |
170176
| promises.js:3:17:5:4 | new Pro ... );\\n }) | promises.js:3:39:3:45 | resolve |
171177
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:10:31:10:33 | res |
@@ -210,4 +216,7 @@ flow
210216
| flow.js:2:15:2:22 | "source" | flow.js:119:86:119:86 | x |
211217
| flow.js:2:15:2:22 | "source" | flow.js:123:58:123:58 | x |
212218
| flow.js:2:15:2:22 | "source" | flow.js:125:59:125:59 | x |
219+
| flow.js:2:15:2:22 | "source" | flow.js:129:69:129:69 | x |
220+
| flow.js:2:15:2:22 | "source" | flow.js:131:43:131:43 | x |
221+
exclusiveTaintFlow
213222
| interflow.js:3:18:3:25 | "source" | interflow.js:18:10:18:14 | error |

0 commit comments

Comments
 (0)