mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
custom load/store steps to implement promise flow
This commit is contained in:
@@ -125,216 +125,159 @@ class AggregateES2015PromiseDefinition extends PromiseCreationCall {
|
||||
*/
|
||||
private module PromiseFlow {
|
||||
/**
|
||||
* A promise from which data-flow can flow into or out of.
|
||||
*
|
||||
* This promise can both be a promise created by e.g. `new Promise(..)` or `Promise.resolve(..)`,
|
||||
* or the result from calling a method on a promise e.g. `promise.then(..)`.
|
||||
*
|
||||
* The 4 methods in this class describe that ordinary and exceptional flow can flow into and out of this promise.
|
||||
* Gets the pseudo-field used to describe resolved values in a promise.
|
||||
*/
|
||||
private abstract class PromiseNode extends DataFlow::SourceNode {
|
||||
|
||||
/**
|
||||
* Get a DataFlow::Node for a value that this promise is resolved with.
|
||||
* The value is sent either to a chained promise, or to an `await` expression.
|
||||
*
|
||||
* The value is e.g. an argument to `resolve(..)`, or a return value from a `.then(..)` handler.
|
||||
*/
|
||||
DataFlow::Node getASentResolveValue() { none() }
|
||||
|
||||
/**
|
||||
* Get the DataFlow::Node that receives the value that this promise has been resolved with.
|
||||
*
|
||||
* E.g. the `x` in `promise.then((x) => ..)`.
|
||||
*/
|
||||
DataFlow::Node getReceivedResolveValue() { none() }
|
||||
|
||||
/**
|
||||
* Get a DataFlow::Node for a value that this promise is rejected with.
|
||||
* The value is sent either to a chained promise, or thrown by an `await` expression.
|
||||
*
|
||||
* The value is e.g. an argument to `reject(..)`, or an exception thrown by the promise executor.
|
||||
*/
|
||||
DataFlow::Node getASentRejectValue() { none() }
|
||||
|
||||
/**
|
||||
* Get the DataFlow::Node that receives the value that this promise has been rejected with.
|
||||
*
|
||||
* E.g. the `x` in `promise.catch((x) => ..)`.
|
||||
*/
|
||||
DataFlow::Node getReceivedRejectValue() { none() }
|
||||
string resolveField() {
|
||||
result = "$PromiseResolveField$"
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A PromiseNode for a PromiseDefinition.
|
||||
* E.g. `new Promise(..)`.
|
||||
* Gets the pseudo-field used to describe rejected values in a promise.
|
||||
*/
|
||||
private class PromiseDefinitionNode extends PromiseNode {
|
||||
string rejectField() {
|
||||
result = "$PromiseRejectField$"
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow step describing a promise definition.
|
||||
*
|
||||
* The resolved/rejected value is written to a pseudo-field on the promise.
|
||||
*/
|
||||
class PromiseDefitionStep extends DataFlow::AdditionalFlowStep {
|
||||
PromiseDefinition promise;
|
||||
|
||||
PromiseDefinitionNode() { this = promise }
|
||||
|
||||
override DataFlow::Node getASentResolveValue() {
|
||||
result = promise.getResolveParameter().getACall().getArgument(0)
|
||||
PromiseDefitionStep() {
|
||||
this = promise
|
||||
}
|
||||
|
||||
override DataFlow::Node getASentRejectValue() {
|
||||
result = promise.getRejectParameter().getACall().getArgument(0)
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
pred = promise.getResolveParameter().getACall().getArgument(0) and
|
||||
succ = this
|
||||
or
|
||||
result = promise.getExecutor().getExceptionalReturn()
|
||||
prop = rejectField() and
|
||||
(
|
||||
pred = promise.getRejectParameter().getACall().getArgument(0) or
|
||||
pred = promise.getExecutor().getExceptionalReturn()
|
||||
) and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A PromiseNode for a call that creates a promise.
|
||||
* E.g. `Promise.resolve(..)` or `Promise.all(..)`.
|
||||
* A flow step describing the a Promise.resolve (and similar) call.
|
||||
*/
|
||||
private class PromiseCreationNode extends PromiseNode {
|
||||
class CreationStep extends DataFlow::AdditionalFlowStep {
|
||||
PromiseCreationCall promise;
|
||||
|
||||
PromiseCreationNode() { this = promise }
|
||||
|
||||
override DataFlow::Node getASentResolveValue() {
|
||||
exists(DataFlow::Node value | value = promise.getValue() |
|
||||
not value instanceof PromiseNode and
|
||||
result = value
|
||||
or
|
||||
result = value.(PromiseNode).getASentResolveValue()
|
||||
)
|
||||
CreationStep() {
|
||||
this = promise
|
||||
}
|
||||
|
||||
override DataFlow::Node getASentRejectValue() {
|
||||
result = promise.getValue().(PromiseNode).getASentRejectValue()
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
pred = promise.getValue() and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node referring to a PromiseNode through type-tracking.
|
||||
* A load step loading the pseudo-field describing that the promise is either resolved or rejected.
|
||||
* A resolved value is forwarding as the resulting value of the `await` expression,
|
||||
* and a rejected value is thrown as a exception.
|
||||
*/
|
||||
private class TrackedPromiseNode extends PromiseNode {
|
||||
PromiseNode base;
|
||||
TrackedPromiseNode() {
|
||||
this = trackPromise(DataFlow::TypeTracker::end(), base) and
|
||||
not this instanceof PromiseDefinitionNode and
|
||||
not this instanceof PromiseCreationNode
|
||||
class AwaitStep extends DataFlow::AdditionalFlowStep {
|
||||
DataFlow::Node operand;
|
||||
AwaitExpr await;
|
||||
AwaitStep() {
|
||||
this.getEnclosingExpr() = await and
|
||||
operand.getEnclosingExpr() = await.getOperand()
|
||||
}
|
||||
|
||||
override DataFlow::Node getASentResolveValue() { result = base.getASentResolveValue() }
|
||||
override DataFlow::Node getReceivedResolveValue() { result = base.getReceivedResolveValue() }
|
||||
override DataFlow::Node getASentRejectValue() { result = base.getASentRejectValue() }
|
||||
override DataFlow::Node getReceivedRejectValue() { result = base.getReceivedRejectValue() }
|
||||
override predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
succ = this and
|
||||
pred = operand.getALocalSource()
|
||||
or
|
||||
prop = rejectField() and
|
||||
succ = await.getExceptionTarget() and
|
||||
pred = operand.getALocalSource()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow step describing the data-flow related to the `.then` method of a promise.
|
||||
*/
|
||||
class ThenStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
|
||||
ThenStep() {
|
||||
this.getMethodName() = "then"
|
||||
}
|
||||
|
||||
override predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
pred = getReceiver().getALocalSource() and
|
||||
succ = getCallback(0).getParameter(0)
|
||||
or
|
||||
prop = rejectField() and
|
||||
pred = getReceiver().getALocalSource() and
|
||||
succ = getCallback(1).getParameter(0)
|
||||
}
|
||||
|
||||
override predicate copyProperty(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
not exists(this.getArgument(1)) and
|
||||
prop = rejectField() and
|
||||
pred = getReceiver().getALocalSource() and
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
pred = getCallback([0..1]).getAReturn() and
|
||||
succ = this
|
||||
or
|
||||
prop = rejectField() and
|
||||
pred = getCallback([0..1]).getExceptionalReturn() and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
private DataFlow::SourceNode trackPromise(DataFlow::TypeTracker t, PromiseNode promise) {
|
||||
t.start() and result = promise
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = trackPromise(t2, promise).track(t2, t))
|
||||
}
|
||||
|
||||
/**
|
||||
* A PromiseNode that is a method call on an existing PromiseNode.
|
||||
* E.g. `promise.then(..)`.
|
||||
* A flow step describing the data-flow related to the `.catch` method of a promise.
|
||||
*/
|
||||
private abstract class ChainedPromiseNode extends PromiseNode, DataFlow::MethodCallNode {
|
||||
PromiseNode base;
|
||||
|
||||
ChainedPromiseNode() { this = base.getAMethodCall(_) }
|
||||
|
||||
PromiseNode getBase() { result = base }
|
||||
}
|
||||
|
||||
/**
|
||||
* A PromiseNode for the `.then(..)` method on an existing promise.
|
||||
*/
|
||||
private class PromiseThenNode extends ChainedPromiseNode {
|
||||
PromiseThenNode() { this = base.getAMethodCall("then") }
|
||||
|
||||
override DataFlow::Node getASentResolveValue() {
|
||||
exists(DataFlow::Node ret | ret = this.getCallback(0).getAReturn() |
|
||||
if ret instanceof PromiseNode
|
||||
then result = ret.(PromiseNode).getReceivedResolveValue()
|
||||
else result = ret
|
||||
)
|
||||
class CatchStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
|
||||
CatchStep() {
|
||||
this.getMethodName() = "catch"
|
||||
}
|
||||
|
||||
override DataFlow::Node getASentRejectValue() {
|
||||
not exists(this.getCallback(1)) and result = base.getASentRejectValue()
|
||||
or
|
||||
result = this.getCallback([0..1]).getExceptionalReturn()
|
||||
override predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = rejectField() and
|
||||
pred = getReceiver().getALocalSource() and
|
||||
succ = getCallback(0).getParameter(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getReceivedResolveValue() { result = this.getCallback(0).getParameter(0) }
|
||||
override predicate copyProperty(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
pred = getReceiver().getALocalSource() and
|
||||
succ = this
|
||||
}
|
||||
|
||||
override DataFlow::Node getReceivedRejectValue() { result = this.getCallback(1).getParameter(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A PromiseNode for the `.finally(..)` method on an existing promise.
|
||||
*/
|
||||
private class PromiseFinallyNode extends ChainedPromiseNode {
|
||||
PromiseFinallyNode() { this = base.getAMethodCall("finally") }
|
||||
|
||||
override DataFlow::Node getASentResolveValue() { result = base.getASentResolveValue() }
|
||||
|
||||
override DataFlow::Node getASentRejectValue() {
|
||||
result = base.getASentRejectValue()
|
||||
or
|
||||
result = this.getCallback(0).getExceptionalReturn()
|
||||
override predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = rejectField() and
|
||||
pred = getCallback([0..1]).getExceptionalReturn() and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A PromiseNode for the `.catch(..)` method on an existing promise.
|
||||
* A flow step describing the data-flow related to the `.finally` method of a promise.
|
||||
*/
|
||||
private class PromiseCatchNode extends ChainedPromiseNode {
|
||||
PromiseCatchNode() { this = base.getAMethodCall("catch") }
|
||||
|
||||
override DataFlow::Node getASentResolveValue() {
|
||||
exists(DataFlow::Node ret | ret = this.getCallback(0).getAReturn() |
|
||||
if ret instanceof PromiseNode
|
||||
then result = ret.(PromiseNode).getReceivedResolveValue()
|
||||
else result = ret
|
||||
)
|
||||
or
|
||||
result = base.getASentResolveValue()
|
||||
class FinallyStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
|
||||
FinallyStep() {
|
||||
this.getMethodName() = "finally"
|
||||
}
|
||||
|
||||
override DataFlow::Node getASentRejectValue() { result = this.getCallback(0).getExceptionalReturn() }
|
||||
|
||||
override DataFlow::Node getReceivedResolveValue() { none() }
|
||||
|
||||
override DataFlow::Node getReceivedRejectValue() { result = this.getCallback(0).getParameter(0) }
|
||||
}
|
||||
|
||||
|
||||
private ChainedPromiseNode getAChainedPromise(PromiseNode p) { result.getBase() = p}
|
||||
|
||||
/**
|
||||
* A data flow edge from a promise resolve/reject to the corresponding handler (or `await` expression).
|
||||
*/
|
||||
private class PromiseFlowStep extends DataFlow::AdditionalFlowStep {
|
||||
PromiseNode promise;
|
||||
|
||||
PromiseFlowStep() { this = promise }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = promise.getASentResolveValue() and
|
||||
succ = getAChainedPromise(promise).getReceivedResolveValue()
|
||||
or
|
||||
pred = promise.getASentRejectValue() and
|
||||
succ = getAChainedPromise(promise).getReceivedRejectValue()
|
||||
or
|
||||
pred = promise.getASentResolveValue() and
|
||||
exists(DataFlow::SourceNode awaitNode |
|
||||
awaitNode.asExpr().(AwaitExpr).getOperand() = promise.asExpr() and
|
||||
succ = awaitNode
|
||||
)
|
||||
or
|
||||
pred = promise.getASentRejectValue() and
|
||||
exists(DataFlow::SourceNode awaitNode |
|
||||
awaitNode.asExpr().(AwaitExpr).getOperand() = promise.asExpr() and
|
||||
succ = awaitNode.asExpr().getExceptionTarget()
|
||||
)
|
||||
override predicate copyProperty(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
(prop = resolveField() or prop = rejectField()) and
|
||||
pred = getReceiver().getALocalSource() and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +223,21 @@ abstract class Configuration extends string {
|
||||
predicate hasFlowPath(SourcePathNode source, SinkPathNode sink) {
|
||||
flowsTo(source, _, sink, _, this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `pred` should be stored in the object `succ` under the property `prop`.
|
||||
*/
|
||||
predicate isAdditionalStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
|
||||
*/
|
||||
predicate isAdditionalLoadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
|
||||
*/
|
||||
predicate isAdditionalCopyPropertyStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,6 +464,24 @@ abstract class AdditionalFlowStep extends DataFlow::Node {
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `pred` should be stored in the object `succ` under the property `prop`.
|
||||
*/
|
||||
cached
|
||||
predicate store(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
|
||||
*/
|
||||
cached
|
||||
predicate load(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
|
||||
*/
|
||||
cached
|
||||
predicate copyProperty(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -551,6 +584,13 @@ private predicate exploratoryFlowStep(
|
||||
basicFlowStep(pred, succ, _, cfg) or
|
||||
basicStoreStep(pred, succ, _) or
|
||||
basicLoadStep(pred, succ, _) or
|
||||
|
||||
any(AdditionalFlowStep s).store(pred, succ, _) or
|
||||
cfg.isAdditionalStoreStep(pred, succ, _) or
|
||||
any(AdditionalFlowStep s).load(pred, succ, _) or
|
||||
cfg.isAdditionalLoadStep(pred, succ, _) or
|
||||
any(AdditionalFlowStep s).copyProperty(pred, succ, _) or
|
||||
cfg.isAdditionalCopyPropertyStep(pred, succ, _) or
|
||||
// the following two disjuncts taken together over-approximate flow through
|
||||
// higher-order calls
|
||||
callback(pred, succ) or
|
||||
@@ -712,6 +752,12 @@ private predicate storeStep(
|
||||
basicStoreStep(pred, succ, prop) and
|
||||
summary = PathSummary::level()
|
||||
or
|
||||
any(AdditionalFlowStep s).store(pred, succ, prop) and
|
||||
summary = PathSummary::level()
|
||||
or
|
||||
cfg.isAdditionalStoreStep(pred, succ, prop) and
|
||||
summary = PathSummary::level()
|
||||
or
|
||||
exists(Function f, DataFlow::Node mid |
|
||||
// `f` stores its parameter `pred` in property `prop` of a value that flows back to the caller,
|
||||
// and `succ` is an invocation of `f`
|
||||
@@ -767,6 +813,12 @@ private predicate loadStep(
|
||||
basicLoadStep(pred, succ, prop) and
|
||||
summary = PathSummary::level()
|
||||
or
|
||||
any(AdditionalFlowStep s).load(pred, succ, prop) and
|
||||
summary = PathSummary::level()
|
||||
or
|
||||
cfg.isAdditionalLoadStep(pred, succ, prop) and
|
||||
summary = PathSummary::level()
|
||||
or
|
||||
exists(Function f, DataFlow::PropRead read |
|
||||
parameterPropRead(f, succ, pred, prop, read, cfg) and
|
||||
reachesReturn(f, read, cfg, summary)
|
||||
@@ -804,13 +856,31 @@ pragma[noinline]
|
||||
private predicate flowThroughProperty(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::Configuration cfg, PathSummary summary
|
||||
) {
|
||||
exists(string prop, DataFlow::Node base, PathSummary oldSummary, PathSummary newSummary |
|
||||
reachableFromStoreBase(prop, pred, base, cfg, oldSummary) and
|
||||
loadStep(base, succ, prop, cfg, newSummary) and
|
||||
exists(string prop, DataFlow::Node storeBase, DataFlow::Node loadBase, PathSummary oldSummary, PathSummary newSummary |
|
||||
reachableFromStoreBase(prop, pred, storeBase, cfg, oldSummary) and
|
||||
(storeBase = loadBase or existsCopyProperty(storeBase, loadBase, prop)) and
|
||||
loadStep(loadBase, succ, prop, cfg, newSummary) and
|
||||
summary = oldSummary.append(newSummary)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` is copied from `fromNode` to `toNode` using at least 1 step.
|
||||
*
|
||||
* The recursion of this predicate has been unfolded once compared to a naive implementation in order to avoid having no constraint on `prop`.
|
||||
* Therefore a caller of this predicate should also test whether the `toNode` and `fromNode` are equal.
|
||||
*/
|
||||
private predicate existsCopyProperty(DataFlow::Node fromNode, DataFlow::Node toNode, string prop) {
|
||||
exists(DataFlow::AdditionalFlowStep step, DataFlow::Node mid |
|
||||
step.copyProperty(fromNode, mid, prop) and
|
||||
(
|
||||
existsCopyProperty(mid, toNode, prop)
|
||||
or
|
||||
mid = toNode
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` and `cb` are passed as arguments to a function which in turn
|
||||
* invokes `cb`, passing `arg` as its `i`th argument.
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate flowSteps(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
any(DataFlow::AdditionalFlowStep step).step(pred, succ)
|
||||
}
|
||||
49
javascript/ql/test/library-tests/Promises/flow.js
Normal file
49
javascript/ql/test/library-tests/Promises/flow.js
Normal file
@@ -0,0 +1,49 @@
|
||||
(async function () {
|
||||
var source = "source";
|
||||
|
||||
var p1 = Promise.resolve(source);
|
||||
sink(await p1); // NOT OK
|
||||
|
||||
var p2 = new Promise((resolve, reject) => resolve(source));
|
||||
sink(await p2); // NOT OK
|
||||
|
||||
var p3 = new Promise((resolve, reject) => reject(source));
|
||||
sink(await p3); // OK!
|
||||
|
||||
var p4 = new Promise((resolve, reject) => reject(source));
|
||||
try {
|
||||
var foo = await p4;
|
||||
} catch(e) {
|
||||
sink(e); // NOT OK!
|
||||
}
|
||||
|
||||
Promise.resolve(source).then(x => sink(x)); // NOT OK!
|
||||
|
||||
Promise.resolve(source).then(x => foo(x), y => sink(y)); // OK!
|
||||
|
||||
new Promise((resolve, reject) => reject(source)).then(x => sink(x)); // OK!
|
||||
|
||||
new Promise((resolve, reject) => reject(source)).then(x => foo(x), y => sink(y)); // NOT OK!
|
||||
|
||||
Promise.resolve("foo").then(x => source).then(z => sink(z)); // NOT OK!
|
||||
|
||||
Promise.resolve(source).then(x => "foo").then(z => sink(z)); // OK!
|
||||
|
||||
new Promise((resolve, reject) => reject(source)).catch(x => sink(x)); // NOT OK!
|
||||
|
||||
Promise.resolve(source).catch(() => {}).then(a => sink(a)); // NOT OK!
|
||||
|
||||
var p5 = Promise.resolve(source);
|
||||
var p6 = p5.catch(() => {});
|
||||
var p7 = p6.then(a => sink(a)); // NOT OK!
|
||||
|
||||
new Promise((resolve, reject) => reject(source)).then(() => {}).catch(x => sink(x)); // NOT OK!
|
||||
|
||||
new Promise((resolve, reject) => reject(source)).then(() => {}, () => {}).catch(x => sink(x)); // OK!
|
||||
|
||||
Promise.resolve(source).catch(() => {}).catch(() => {}).catch(() => {}).then(a => sink(a)); // NOT OK!
|
||||
|
||||
Promise.resolve(source).finally(() => {}).then(a => sink(a)); // NOT OK!
|
||||
|
||||
new Promise(() => {throw source}).catch(x => sink(x)); // NOT OK!
|
||||
})();
|
||||
17
javascript/ql/test/library-tests/Promises/flow.qll
Normal file
17
javascript/ql/test/library-tests/Promises/flow.qll
Normal file
@@ -0,0 +1,17 @@
|
||||
import javascript
|
||||
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "PromiseFlowTestingConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.getEnclosingExpr().getStringValue() = "source"
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
any(DataFlow::InvokeNode call | call.getCalleeName() = "sink").getAnArgument() = sink
|
||||
}
|
||||
}
|
||||
|
||||
query predicate flow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
any(Configuration a).hasFlow(source, sink)
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
(async function () {
|
||||
function throws(resolve, reject) {
|
||||
throw new Error()
|
||||
}
|
||||
new Promise(throws)
|
||||
.catch((e) => console.log(e));
|
||||
|
||||
new Promise(throws)
|
||||
.then((val) => console.log(val), (error) => console.log(error));
|
||||
|
||||
try {
|
||||
await new Promise(throws);
|
||||
} catch (e2) {
|
||||
console.log(e2);
|
||||
}
|
||||
|
||||
new Promise((resolve, reject) => reject(3))
|
||||
.catch((e3) => console.log(e3));
|
||||
|
||||
try {
|
||||
await new Promise((resolve, reject) => reject(4));
|
||||
} catch(e4) {
|
||||
console.log(e4);
|
||||
}
|
||||
|
||||
new Promise(throws)
|
||||
.then(() => {})
|
||||
.catch((e5) => console.log(e5));
|
||||
|
||||
|
||||
new Promise(throws)
|
||||
.then(() => {})
|
||||
.catch((e6) => console.log(e6))
|
||||
.catch((e7) => console.log(e7));
|
||||
|
||||
var foo = await new Promise((resolve, reject) => resolve(8))
|
||||
|
||||
var bar = await new Promise((resolve, reject) => resolve(9)).then((x) => x + 2);
|
||||
|
||||
var p = Promise.resolve(3);
|
||||
var baz = await p.then((val) => val * 2);
|
||||
|
||||
var p2 = new Promise((resolve, reject) => {
|
||||
if (Math.random() > 0.5) {
|
||||
resolve(13);
|
||||
} else {
|
||||
reject(14);
|
||||
}
|
||||
});
|
||||
var quz = await p2.then(val => val * 4).catch(e => e * 3);
|
||||
|
||||
function returnsPromise() {
|
||||
return Promise.resolve(3);
|
||||
}
|
||||
var a = await returnsPromise();
|
||||
})();
|
||||
1
javascript/ql/test/library-tests/Promises/options
Normal file
1
javascript/ql/test/library-tests/Promises/options
Normal file
@@ -0,0 +1 @@
|
||||
semmle-extractor-options: --experimental
|
||||
@@ -1,27 +1,34 @@
|
||||
test_ResolvedPromiseDefinition
|
||||
| flowsteps.js:40:11:40:28 | Promise.resolve(3) | flowsteps.js:40:27:40:27 | 3 |
|
||||
| flowsteps.js:53:12:53:29 | Promise.resolve(3) | flowsteps.js:53:28:53:28 | 3 |
|
||||
| flow.js:4:11:4:33 | Promise ... source) | flow.js:4:27:4:32 | source |
|
||||
| flow.js:20:2:20:24 | Promise ... source) | flow.js:20:18:20:23 | source |
|
||||
| flow.js:22:2:22:24 | Promise ... source) | flow.js:22:18:22:23 | source |
|
||||
| flow.js:28:2:28:23 | Promise ... ("foo") | flow.js:28:18:28:22 | "foo" |
|
||||
| flow.js:30:2:30:24 | Promise ... source) | flow.js:30:18:30:23 | source |
|
||||
| flow.js:34:2:34:24 | Promise ... source) | flow.js:34:18:34:23 | source |
|
||||
| flow.js:36:11:36:33 | Promise ... source) | flow.js:36:27:36:32 | source |
|
||||
| flow.js:44:2:44:24 | Promise ... source) | flow.js:44:18:44:23 | source |
|
||||
| flow.js:46:2:46:24 | Promise ... source) | flow.js:46:18:46:23 | source |
|
||||
| promises.js:53:19:53:41 | Promise ... source) | promises.js:53:35:53:40 | source |
|
||||
| promises.js:62:19:62:41 | Promise ... source) | promises.js:62:35:62:40 | source |
|
||||
| promises.js:71:5:71:27 | Promise ... source) | promises.js:71:21:71:26 | source |
|
||||
test_PromiseDefinition_getARejectHandler
|
||||
| flowsteps.js:5:3:5:21 | new Promise(throws) | flowsteps.js:6:12:6:32 | (e) => ... .log(e) |
|
||||
| flowsteps.js:8:3:8:21 | new Promise(throws) | flowsteps.js:9:38:9:66 | (error) ... (error) |
|
||||
| flowsteps.js:17:3:17:45 | new Pro ... ect(3)) | flowsteps.js:18:12:18:34 | (e3) => ... log(e3) |
|
||||
| flow.js:26:2:26:49 | new Pro ... ource)) | flow.js:26:69:26:80 | y => sink(y) |
|
||||
| flow.js:32:2:32:49 | new Pro ... ource)) | flow.js:32:57:32:68 | x => sink(x) |
|
||||
| flow.js:42:2:42:49 | new Pro ... ource)) | flow.js:42:66:42:73 | () => {} |
|
||||
| flow.js:48:2:48:34 | new Pro ... ource}) | flow.js:48:42:48:53 | x => sink(x) |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:20:6:22:3 | (v) => ... v;\\n } |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:23:18:25:3 | (v) => ... v;\\n } |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:26:20:28:3 | (v) => ... v;\\n } |
|
||||
test_PromiseDefinition_getExecutor
|
||||
| flowsteps.js:5:3:5:21 | new Promise(throws) | flowsteps.js:2:3:4:3 | functio ... r()\\n } |
|
||||
| flowsteps.js:8:3:8:21 | new Promise(throws) | flowsteps.js:2:3:4:3 | functio ... r()\\n } |
|
||||
| flowsteps.js:12:11:12:29 | new Promise(throws) | flowsteps.js:2:3:4:3 | functio ... r()\\n } |
|
||||
| flowsteps.js:17:3:17:45 | new Pro ... ect(3)) | flowsteps.js:17:15:17:44 | (resolv ... ject(3) |
|
||||
| flowsteps.js:21:11:21:53 | new Pro ... ect(4)) | flowsteps.js:21:23:21:52 | (resolv ... ject(4) |
|
||||
| flowsteps.js:26:3:26:21 | new Promise(throws) | flowsteps.js:2:3:4:3 | functio ... r()\\n } |
|
||||
| flowsteps.js:31:3:31:21 | new Promise(throws) | flowsteps.js:2:3:4:3 | functio ... r()\\n } |
|
||||
| flowsteps.js:36:19:36:62 | new Pro ... lve(8)) | flowsteps.js:36:31:36:61 | (resolv ... olve(8) |
|
||||
| flowsteps.js:38:19:38:62 | new Pro ... lve(9)) | flowsteps.js:38:31:38:61 | (resolv ... olve(9) |
|
||||
| flowsteps.js:43:12:49:4 | new Pro ... }\\n }) | flowsteps.js:43:24:49:3 | (resolv ... }\\n } |
|
||||
| flow.js:7:11:7:59 | new Pro ... ource)) | flow.js:7:23:7:58 | (resolv ... source) |
|
||||
| flow.js:10:11:10:58 | new Pro ... ource)) | flow.js:10:23:10:57 | (resolv ... source) |
|
||||
| flow.js:13:11:13:58 | new Pro ... ource)) | flow.js:13:23:13:57 | (resolv ... source) |
|
||||
| flow.js:24:2:24:49 | new Pro ... ource)) | flow.js:24:14:24:48 | (resolv ... source) |
|
||||
| flow.js:26:2:26:49 | new Pro ... ource)) | flow.js:26:14:26:48 | (resolv ... source) |
|
||||
| flow.js:32:2:32:49 | new Pro ... ource)) | flow.js:32:14:32:48 | (resolv ... source) |
|
||||
| flow.js:40:2:40:49 | new Pro ... ource)) | flow.js:40:14:40:48 | (resolv ... source) |
|
||||
| flow.js:42:2:42:49 | new Pro ... ource)) | flow.js:42:14:42:48 | (resolv ... source) |
|
||||
| flow.js:48:2:48:34 | new Pro ... ource}) | flow.js:48:14:48:33 | () => {throw source} |
|
||||
| promises.js:3:17:5:4 | new Pro ... );\\n }) | promises.js:3:29:5:3 | functio ... e);\\n } |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:10:30:17:3 | (res, r ... e);\\n } |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:33:31:35:5 | functio ... ;\\n } |
|
||||
@@ -29,103 +36,70 @@ test_PromiseDefinition_getExecutor
|
||||
test_PromiseDefinition_getAFinallyHandler
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:26:20:28:3 | (v) => ... v;\\n } |
|
||||
test_PromiseDefinition
|
||||
| flowsteps.js:5:3:5:21 | new Promise(throws) |
|
||||
| flowsteps.js:8:3:8:21 | new Promise(throws) |
|
||||
| flowsteps.js:12:11:12:29 | new Promise(throws) |
|
||||
| flowsteps.js:17:3:17:45 | new Pro ... ect(3)) |
|
||||
| flowsteps.js:21:11:21:53 | new Pro ... ect(4)) |
|
||||
| flowsteps.js:26:3:26:21 | new Promise(throws) |
|
||||
| flowsteps.js:31:3:31:21 | new Promise(throws) |
|
||||
| flowsteps.js:36:19:36:62 | new Pro ... lve(8)) |
|
||||
| flowsteps.js:38:19:38:62 | new Pro ... lve(9)) |
|
||||
| flowsteps.js:43:12:49:4 | new Pro ... }\\n }) |
|
||||
| flow.js:7:11:7:59 | new Pro ... ource)) |
|
||||
| flow.js:10:11:10:58 | new Pro ... ource)) |
|
||||
| flow.js:13:11:13:58 | new Pro ... ource)) |
|
||||
| flow.js:24:2:24:49 | new Pro ... ource)) |
|
||||
| flow.js:26:2:26:49 | new Pro ... ource)) |
|
||||
| flow.js:32:2:32:49 | new Pro ... ource)) |
|
||||
| flow.js:40:2:40:49 | new Pro ... ource)) |
|
||||
| flow.js:42:2:42:49 | new Pro ... ource)) |
|
||||
| flow.js:48:2:48:34 | new Pro ... ource}) |
|
||||
| promises.js:3:17:5:4 | new Pro ... );\\n }) |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) |
|
||||
test_PromiseDefinition_getAResolveHandler
|
||||
| flowsteps.js:8:3:8:21 | new Promise(throws) | flowsteps.js:9:11:9:35 | (val) = ... og(val) |
|
||||
| flowsteps.js:26:3:26:21 | new Promise(throws) | flowsteps.js:27:11:27:18 | () => {} |
|
||||
| flowsteps.js:31:3:31:21 | new Promise(throws) | flowsteps.js:32:11:32:18 | () => {} |
|
||||
| flowsteps.js:38:19:38:62 | new Pro ... lve(9)) | flowsteps.js:38:69:38:80 | (x) => x + 2 |
|
||||
| flowsteps.js:43:12:49:4 | new Pro ... }\\n }) | flowsteps.js:50:27:50:40 | val => val * 4 |
|
||||
| flow.js:24:2:24:49 | new Pro ... ource)) | flow.js:24:56:24:67 | x => sink(x) |
|
||||
| flow.js:26:2:26:49 | new Pro ... ource)) | flow.js:26:56:26:66 | x => foo(x) |
|
||||
| flow.js:40:2:40:49 | new Pro ... ource)) | flow.js:40:56:40:63 | () => {} |
|
||||
| flow.js:42:2:42:49 | new Pro ... ource)) | flow.js:42:56:42:63 | () => {} |
|
||||
| promises.js:3:17:5:4 | new Pro ... );\\n }) | promises.js:6:16:8:3 | functio ... al;\\n } |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:18:17:20:3 | (v) => ... v;\\n } |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:26:20:28:3 | (v) => ... v;\\n } |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:36:18:38:5 | functio ... ;\\n } |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:46:18:48:5 | functio ... ;\\n } |
|
||||
test_PromiseDefinition_getRejectParameter
|
||||
| flowsteps.js:5:3:5:21 | new Promise(throws) | flowsteps.js:2:28:2:33 | reject |
|
||||
| flowsteps.js:8:3:8:21 | new Promise(throws) | flowsteps.js:2:28:2:33 | reject |
|
||||
| flowsteps.js:12:11:12:29 | new Promise(throws) | flowsteps.js:2:28:2:33 | reject |
|
||||
| flowsteps.js:17:3:17:45 | new Pro ... ect(3)) | flowsteps.js:17:25:17:30 | reject |
|
||||
| flowsteps.js:21:11:21:53 | new Pro ... ect(4)) | flowsteps.js:21:33:21:38 | reject |
|
||||
| flowsteps.js:26:3:26:21 | new Promise(throws) | flowsteps.js:2:28:2:33 | reject |
|
||||
| flowsteps.js:31:3:31:21 | new Promise(throws) | flowsteps.js:2:28:2:33 | reject |
|
||||
| flowsteps.js:36:19:36:62 | new Pro ... lve(8)) | flowsteps.js:36:41:36:46 | reject |
|
||||
| flowsteps.js:38:19:38:62 | new Pro ... lve(9)) | flowsteps.js:38:41:38:46 | reject |
|
||||
| flowsteps.js:43:12:49:4 | new Pro ... }\\n }) | flowsteps.js:43:34:43:39 | reject |
|
||||
| flow.js:7:11:7:59 | new Pro ... ource)) | flow.js:7:33:7:38 | reject |
|
||||
| flow.js:10:11:10:58 | new Pro ... ource)) | flow.js:10:33:10:38 | reject |
|
||||
| flow.js:13:11:13:58 | new Pro ... ource)) | flow.js:13:33:13:38 | reject |
|
||||
| flow.js:24:2:24:49 | new Pro ... ource)) | flow.js:24:24:24:29 | reject |
|
||||
| flow.js:26:2:26:49 | new Pro ... ource)) | flow.js:26:24:26:29 | reject |
|
||||
| flow.js:32:2:32:49 | new Pro ... ource)) | flow.js:32:24:32:29 | reject |
|
||||
| flow.js:40:2:40:49 | new Pro ... ource)) | flow.js:40:24:40:29 | reject |
|
||||
| flow.js:42:2:42:49 | new Pro ... ource)) | flow.js:42:24:42:29 | reject |
|
||||
| promises.js:3:17:5:4 | new Pro ... );\\n }) | promises.js:3:48:3:53 | reject |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:10:36:10:38 | rej |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:33:50:33:55 | reject |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:43:48:43:53 | reject |
|
||||
test_PromiseDefinition_getResolveParameter
|
||||
| flowsteps.js:5:3:5:21 | new Promise(throws) | flowsteps.js:2:19:2:25 | resolve |
|
||||
| flowsteps.js:8:3:8:21 | new Promise(throws) | flowsteps.js:2:19:2:25 | resolve |
|
||||
| flowsteps.js:12:11:12:29 | new Promise(throws) | flowsteps.js:2:19:2:25 | resolve |
|
||||
| flowsteps.js:17:3:17:45 | new Pro ... ect(3)) | flowsteps.js:17:16:17:22 | resolve |
|
||||
| flowsteps.js:21:11:21:53 | new Pro ... ect(4)) | flowsteps.js:21:24:21:30 | resolve |
|
||||
| flowsteps.js:26:3:26:21 | new Promise(throws) | flowsteps.js:2:19:2:25 | resolve |
|
||||
| flowsteps.js:31:3:31:21 | new Promise(throws) | flowsteps.js:2:19:2:25 | resolve |
|
||||
| flowsteps.js:36:19:36:62 | new Pro ... lve(8)) | flowsteps.js:36:32:36:38 | resolve |
|
||||
| flowsteps.js:38:19:38:62 | new Pro ... lve(9)) | flowsteps.js:38:32:38:38 | resolve |
|
||||
| flowsteps.js:43:12:49:4 | new Pro ... }\\n }) | flowsteps.js:43:25:43:31 | resolve |
|
||||
| flow.js:7:11:7:59 | new Pro ... ource)) | flow.js:7:24:7:30 | resolve |
|
||||
| flow.js:10:11:10:58 | new Pro ... ource)) | flow.js:10:24:10:30 | resolve |
|
||||
| flow.js:13:11:13:58 | new Pro ... ource)) | flow.js:13:24:13:30 | resolve |
|
||||
| flow.js:24:2:24:49 | new Pro ... ource)) | flow.js:24:15:24:21 | resolve |
|
||||
| flow.js:26:2:26:49 | new Pro ... ource)) | flow.js:26:15:26:21 | resolve |
|
||||
| flow.js:32:2:32:49 | new Pro ... ource)) | flow.js:32:15:32:21 | resolve |
|
||||
| flow.js:40:2:40:49 | new Pro ... ource)) | flow.js:40:15:40:21 | resolve |
|
||||
| flow.js:42:2:42:49 | new Pro ... ource)) | flow.js:42:15:42:21 | resolve |
|
||||
| promises.js:3:17:5:4 | new Pro ... );\\n }) | promises.js:3:39:3:45 | resolve |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:10:31:10:33 | res |
|
||||
| promises.js:33:19:35:6 | new Pro ... \\n }) | promises.js:33:41:33:47 | resolve |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:43:39:43:45 | resolve |
|
||||
test_PromiseDefinition_getACatchHandler
|
||||
| flowsteps.js:5:3:5:21 | new Promise(throws) | flowsteps.js:6:12:6:32 | (e) => ... .log(e) |
|
||||
| flowsteps.js:17:3:17:45 | new Pro ... ect(3)) | flowsteps.js:18:12:18:34 | (e3) => ... log(e3) |
|
||||
| flow.js:32:2:32:49 | new Pro ... ource)) | flow.js:32:57:32:68 | x => sink(x) |
|
||||
| flow.js:48:2:48:34 | new Pro ... ource}) | flow.js:48:42:48:53 | x => sink(x) |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:23:18:25:3 | (v) => ... v;\\n } |
|
||||
flowSteps
|
||||
| flowsteps.js:2:3:4:3 | exceptional return of function throws | flowsteps.js:6:13:6:13 | e |
|
||||
| flowsteps.js:2:3:4:3 | exceptional return of function throws | flowsteps.js:9:39:9:43 | error |
|
||||
| flowsteps.js:2:3:4:3 | exceptional return of function throws | flowsteps.js:13:12:13:13 | e2 |
|
||||
| flowsteps.js:2:3:4:3 | exceptional return of function throws | flowsteps.js:28:13:28:14 | e5 |
|
||||
| flowsteps.js:2:3:4:3 | exceptional return of function throws | flowsteps.js:33:13:33:14 | e6 |
|
||||
| flowsteps.js:17:15:17:44 | exceptional return of anonymous function | flowsteps.js:18:13:18:14 | e3 |
|
||||
| flowsteps.js:17:43:17:43 | 3 | flowsteps.js:18:13:18:14 | e3 |
|
||||
| flowsteps.js:21:23:21:52 | exceptional return of anonymous function | flowsteps.js:22:11:22:12 | e4 |
|
||||
| flowsteps.js:21:51:21:51 | 4 | flowsteps.js:22:11:22:12 | e4 |
|
||||
| flowsteps.js:27:11:27:18 | exceptional return of anonymous function | flowsteps.js:28:13:28:14 | e5 |
|
||||
| flowsteps.js:32:11:32:18 | exceptional return of anonymous function | flowsteps.js:33:13:33:14 | e6 |
|
||||
| flowsteps.js:33:12:33:34 | exceptional return of anonymous function | flowsteps.js:34:13:34:14 | e7 |
|
||||
| flowsteps.js:36:31:36:61 | exceptional return of anonymous function | flowsteps.js:1:2:56:1 | exceptional return of anonymous function |
|
||||
| flowsteps.js:36:60:36:60 | 8 | flowsteps.js:36:13:36:62 | await n ... lve(8)) |
|
||||
| flowsteps.js:38:31:38:61 | exceptional return of anonymous function | flowsteps.js:1:2:56:1 | exceptional return of anonymous function |
|
||||
| flowsteps.js:38:60:38:60 | 9 | flowsteps.js:38:70:38:70 | x |
|
||||
| flowsteps.js:38:69:38:80 | exceptional return of anonymous function | flowsteps.js:1:2:56:1 | exceptional return of anonymous function |
|
||||
| flowsteps.js:38:76:38:80 | x + 2 | flowsteps.js:38:13:38:81 | await n ... x + 2) |
|
||||
| flowsteps.js:40:27:40:27 | 3 | flowsteps.js:41:27:41:29 | val |
|
||||
| flowsteps.js:41:26:41:41 | exceptional return of anonymous function | flowsteps.js:1:2:56:1 | exceptional return of anonymous function |
|
||||
| flowsteps.js:41:35:41:41 | val * 2 | flowsteps.js:41:13:41:42 | await p ... al * 2) |
|
||||
| flowsteps.js:43:24:49:3 | exceptional return of anonymous function | flowsteps.js:50:49:50:49 | e |
|
||||
| flowsteps.js:45:12:45:13 | 13 | flowsteps.js:50:27:50:29 | val |
|
||||
| flowsteps.js:47:11:47:12 | 14 | flowsteps.js:50:49:50:49 | e |
|
||||
| flowsteps.js:50:27:50:40 | exceptional return of anonymous function | flowsteps.js:50:49:50:49 | e |
|
||||
| flowsteps.js:50:34:50:40 | val * 4 | flowsteps.js:50:13:50:59 | await p ... e * 3) |
|
||||
| flowsteps.js:50:49:50:58 | exceptional return of anonymous function | flowsteps.js:1:2:56:1 | exceptional return of anonymous function |
|
||||
| flowsteps.js:50:54:50:58 | e * 3 | flowsteps.js:50:13:50:59 | await p ... e * 3) |
|
||||
| flowsteps.js:53:28:53:28 | 3 | flowsteps.js:55:11:55:32 | await r ... omise() |
|
||||
| promises.js:4:13:4:18 | source | promises.js:6:26:6:28 | val |
|
||||
| promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:20:7:20:7 | v |
|
||||
| promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:23:19:23:19 | v |
|
||||
| promises.js:14:11:14:20 | res_source | promises.js:18:18:18:18 | v |
|
||||
| promises.js:16:11:16:20 | rej_source | promises.js:20:7:20:7 | v |
|
||||
| promises.js:16:11:16:20 | rej_source | promises.js:23:19:23:19 | v |
|
||||
| promises.js:34:17:34:22 | source | promises.js:36:28:36:30 | val |
|
||||
| promises.js:44:17:44:22 | source | promises.js:46:28:46:30 | val |
|
||||
| promises.js:53:35:53:40 | source | promises.js:54:28:54:30 | val |
|
||||
| promises.js:62:35:62:40 | source | promises.js:63:28:63:30 | val |
|
||||
| promises.js:71:21:71:26 | source | promises.js:71:34:71:36 | val |
|
||||
flow
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:5:7:5:14 | await p1 |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:8:7:8:14 | await p2 |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:17:8:17:8 | e |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:20:41:20:41 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:26:79:26:79 | y |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:28:58:28:58 | z |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:32:67:32:67 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:34:57:34:57 | a |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:38:29:38:29 | a |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:40:82:40:82 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:44:89:44:89 | a |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:46:59:46:59 | a |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:48:52:48:52 | x |
|
||||
|
||||
@@ -7,4 +7,4 @@ import PromiseDefinition_getAResolveHandler
|
||||
import PromiseDefinition_getRejectParameter
|
||||
import PromiseDefinition_getResolveParameter
|
||||
import PromiseDefinition_getACatchHandler
|
||||
import Flowsteps
|
||||
import flow
|
||||
Reference in New Issue
Block a user