add additional data-flow edges to data-flow related to promises

This commit is contained in:
Erik Krogh Kristensen
2019-12-19 09:54:00 +01:00
parent ad92d6fe0f
commit ec5896abba
9 changed files with 533 additions and 200 deletions

View File

@@ -1,9 +1,380 @@
/**
* Provides classes for modelling promise libraries.
* Provides classes for modelling promises and their data-flow.
*/
import javascript
/**
* A definition of a `Promise` object.
*/
abstract class PromiseDefinition extends DataFlow::SourceNode {
/** Gets the executor function of this promise object. */
abstract DataFlow::FunctionNode getExecutor();
/** Gets the `resolve` parameter of the executor function. */
DataFlow::ParameterNode getResolveParameter() { result = getExecutor().getParameter(0) }
/** Gets the `reject` parameter of the executor function. */
DataFlow::ParameterNode getRejectParameter() { result = getExecutor().getParameter(1) }
/** Gets the `i`th callback handler installed by method `m`. */
private DataFlow::FunctionNode getAHandler(string m, int i) {
result = getAMethodCall(m).getCallback(i)
}
/**
* Gets a function that handles promise resolution, including both
* `then` handlers and `finally` handlers.
*/
DataFlow::FunctionNode getAResolveHandler() {
result = getAHandler("then", 0) or
result = getAFinallyHandler()
}
/**
* Gets a function that handles promise rejection, including
* `then` handlers, `catch` handlers and `finally` handlers.
*/
DataFlow::FunctionNode getARejectHandler() {
result = getAHandler("then", 1) or
result = getACatchHandler() or
result = getAFinallyHandler()
}
/**
* Gets a `catch` handler of this promise.
*/
DataFlow::FunctionNode getACatchHandler() { result = getAHandler("catch", 0) }
/**
* Gets a `finally` handler of this promise.
*/
DataFlow::FunctionNode getAFinallyHandler() { result = getAHandler("finally", 0) }
}
/** Holds if the `i`th callback handler is installed by method `m`. */
private predicate hasHandler(DataFlow::InvokeNode promise, string m, int i) {
exists(promise.getAMethodCall(m).getCallback(i))
}
/**
* A call that looks like a Promise.
*
* For example, this could be the call `promise(f).then(function(v){...})`
*/
class PromiseCandidate extends DataFlow::InvokeNode {
PromiseCandidate() {
hasHandler(this, "then", [0 .. 1]) or
hasHandler(this, "catch", 0) or
hasHandler(this, "finally", 0)
}
}
/**
* A promise object created by the standard ECMAScript 2015 `Promise` constructor.
*/
private class ES2015PromiseDefinition extends PromiseDefinition, DataFlow::NewNode {
ES2015PromiseDefinition() { this = DataFlow::globalVarRef("Promise").getAnInstantiation() }
override DataFlow::FunctionNode getExecutor() { result = getCallback(0) }
}
/**
* A promise that is created and resolved with one or more value.
*/
abstract class PromiseCreationCall extends DataFlow::CallNode {
/**
* Gets the value this promise is resolved with.
*/
abstract DataFlow::Node getValue();
}
/**
* A promise that is created using a `.resolve()` call.
*/
abstract class ResolvedPromiseDefinition extends PromiseCreationCall { }
/**
* A resolved promise created by the standard ECMAScript 2015 `Promise.resolve` function.
*/
class ResolvedES2015PromiseDefinition extends ResolvedPromiseDefinition {
ResolvedES2015PromiseDefinition() {
this = DataFlow::globalVarRef("Promise").getAMemberCall("resolve")
}
override DataFlow::Node getValue() { result = getArgument(0) }
}
/**
* An aggregated promise produced either by `Promise.all` or `Promise.race`.
*/
class AggregateES2015PromiseDefinition extends PromiseCreationCall {
AggregateES2015PromiseDefinition() {
exists(string m | m = "all" or m = "race" |
this = DataFlow::globalVarRef("Promise").getAMemberCall(m)
)
}
override DataFlow::Node getValue() {
result = getArgument(0).getALocalSource().(DataFlow::ArrayCreationNode).getAnElement()
}
}
/**
* This module defines how data-flow propagates into and out a Promise.
*/
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.
*/
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() }
}
/**
* A PromiseNode for a PromiseDefinition.
* E.g. `new Promise(..)`.
*/
private class PromiseDefinitionNode extends PromiseNode {
PromiseDefinition promise;
PromiseDefinitionNode() { this = promise }
override DataFlow::Node getASentResolveValue() {
result = promise.getResolveParameter().getACall().getArgument(0)
}
override DataFlow::Node getASentRejectValue() {
result = promise.getRejectParameter().getACall().getArgument(0)
or
result = promise.getExecutor().getExceptionalReturn()
}
}
/**
* A PromiseNode for a call that creates a promise.
* E.g. `Promise.resolve(..)` or `Promise.all(..)`.
*/
private class PromiseCreationNode extends PromiseNode {
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()
)
}
override DataFlow::Node getASentRejectValue() {
result = promise.getValue().(PromiseNode).getASentRejectValue()
}
}
/**
* A node referring to a PromiseNode through type-tracking.
*/
private class TrackedPromiseNode extends PromiseNode {
PromiseNode base;
TrackedPromiseNode() {
this = trackPromise(DataFlow::TypeTracker::end(), base) and
not this instanceof PromiseDefinitionNode and
not this instanceof PromiseCreationNode
}
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() }
}
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(..)`.
*/
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
)
}
override DataFlow::Node getASentRejectValue() {
not exists(this.getCallback(1)) and result = base.getASentRejectValue()
or
result = this.getCallback([0..1]).getExceptionalReturn()
}
override DataFlow::Node getReceivedResolveValue() { result = this.getCallback(0).getParameter(0) }
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()
}
}
/**
* A PromiseNode for the `.catch(..)` method on an existing 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()
}
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()
)
}
}
}
/**
* Holds if taint propagates from `pred` to `succ` through promises.
*/
predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
// from `x` to `new Promise((res, rej) => res(x))`
pred = succ.(PromiseDefinition).getResolveParameter().getACall().getArgument(0)
or
// from `x` to `Promise.resolve(x)`
pred = succ.(PromiseCreationCall).getValue()
or
exists(DataFlow::MethodCallNode thn, DataFlow::FunctionNode cb |
thn.getMethodName() = "then" and cb = thn.getCallback(0)
|
// from `p` to `x` in `p.then(x => ...)`
pred = thn.getReceiver() and
succ = cb.getParameter(0)
or
// from `v` to `p.then(x => return v)`
pred = cb.getAReturn() and
succ = thn
)
}
/**
* An additional taint step that involves promises.
*/
private class PromiseTaintStep extends TaintTracking::AdditionalTaintStep {
DataFlow::Node source;
PromiseTaintStep() { promiseTaintStep(source, this) }
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = source and succ = this
}
}
/**
* Provides classes for working with the `bluebird` library (http://bluebirdjs.com).
*/

View File

@@ -76,191 +76,6 @@ private class AnalyzedThisInArrayIterationFunction extends AnalyzedNode, DataFlo
}
}
/**
* A definition of a `Promise` object.
*/
abstract class PromiseDefinition extends DataFlow::SourceNode {
/** Gets the executor function of this promise object. */
abstract DataFlow::FunctionNode getExecutor();
/** Gets the `resolve` parameter of the executor function. */
DataFlow::ParameterNode getResolveParameter() { result = getExecutor().getParameter(0) }
/** Gets the `reject` parameter of the executor function. */
DataFlow::ParameterNode getRejectParameter() { result = getExecutor().getParameter(1) }
/** Gets the `i`th callback handler installed by method `m`. */
private DataFlow::FunctionNode getAHandler(string m, int i) {
result = getAMethodCall(m).getCallback(i)
}
/**
* Gets a function that handles promise resolution, including both
* `then` handlers and `finally` handlers.
*/
DataFlow::FunctionNode getAResolveHandler() {
result = getAHandler("then", 0) or
result = getAFinallyHandler()
}
/**
* Gets a function that handles promise rejection, including
* `then` handlers, `catch` handlers and `finally` handlers.
*/
DataFlow::FunctionNode getARejectHandler() {
result = getAHandler("then", 1) or
result = getACatchHandler() or
result = getAFinallyHandler()
}
/**
* Gets a `catch` handler of this promise.
*/
DataFlow::FunctionNode getACatchHandler() { result = getAHandler("catch", 0) }
/**
* Gets a `finally` handler of this promise.
*/
DataFlow::FunctionNode getAFinallyHandler() { result = getAHandler("finally", 0) }
}
/** Holds if the `i`th callback handler is installed by method `m`. */
private predicate hasHandler(DataFlow::InvokeNode promise, string m, int i) {
exists(promise.getAMethodCall(m).getCallback(i))
}
/**
* A call that looks like a Promise.
*
* For example, this could be the call `promise(f).then(function(v){...})`
*/
class PromiseCandidate extends DataFlow::InvokeNode {
PromiseCandidate() {
hasHandler(this, "then", [0 .. 1]) or
hasHandler(this, "catch", 0) or
hasHandler(this, "finally", 0)
}
}
/**
* A promise object created by the standard ECMAScript 2015 `Promise` constructor.
*/
private class ES2015PromiseDefinition extends PromiseDefinition, DataFlow::NewNode {
ES2015PromiseDefinition() { this = DataFlow::globalVarRef("Promise").getAnInstantiation() }
override DataFlow::FunctionNode getExecutor() { result = getCallback(0) }
}
/**
* A promise that is created and resolved with one or more value.
*/
abstract class PromiseCreationCall extends DataFlow::CallNode {
/**
* Gets the value this promise is resolved with.
*/
abstract DataFlow::Node getValue();
}
/**
* A promise that is created using a `.resolve()` call.
*/
abstract class ResolvedPromiseDefinition extends PromiseCreationCall {}
/**
* A resolved promise created by the standard ECMAScript 2015 `Promise.resolve` function.
*/
class ResolvedES2015PromiseDefinition extends ResolvedPromiseDefinition {
ResolvedES2015PromiseDefinition() {
this = DataFlow::globalVarRef("Promise").getAMemberCall("resolve")
}
override DataFlow::Node getValue() { result = getArgument(0) }
}
/**
* An aggregated promise produced either by `Promise.all` or `Promise.race`.
*/
class AggregateES2015PromiseDefinition extends PromiseCreationCall {
AggregateES2015PromiseDefinition() {
exists(string m | m = "all" or m = "race" |
this = DataFlow::globalVarRef("Promise").getAMemberCall(m)
)
}
override DataFlow::Node getValue() {
result = getArgument(0).getALocalSource().(DataFlow::ArrayCreationNode).getAnElement()
}
}
/**
* A data flow edge from a promise reaction to the corresponding handler.
*/
private class PromiseFlowStep extends DataFlow::AdditionalFlowStep {
PromiseDefinition p;
PromiseFlowStep() { this = p }
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = p.getResolveParameter().getACall().getArgument(0) and
succ = p.getAResolveHandler().getParameter(0)
or
pred = p.getRejectParameter().getACall().getArgument(0) and
succ = p.getARejectHandler().getParameter(0)
}
}
/**
* A data flow edge from the exceptional return of the promise executor to the promise catch handler.
* This only adds an edge from the exceptional return of the promise executor to a `.catch()` handler.
*/
private class PromiseExceptionalStep extends DataFlow::AdditionalFlowStep {
PromiseDefinition promise;
PromiseExceptionalStep() {
promise = this
}
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = promise.getExecutor().getExceptionalReturn() and
succ = promise.getACatchHandler().getParameter(0)
}
}
/**
* Holds if taint propagates from `pred` to `succ` through promises.
*/
predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
// from `x` to `new Promise((res, rej) => res(x))`
pred = succ.(PromiseDefinition).getResolveParameter().getACall().getArgument(0)
or
// from `x` to `Promise.resolve(x)`
pred = succ.(PromiseCreationCall).getValue()
or
exists(DataFlow::MethodCallNode thn, DataFlow::FunctionNode cb |
thn.getMethodName() = "then" and cb = thn.getCallback(0)
|
// from `p` to `x` in `p.then(x => ...)`
pred = thn.getReceiver() and
succ = cb.getParameter(0)
or
// from `v` to `p.then(x => return v)`
pred = cb.getAReturn() and
succ = thn
)
}
/**
* An additional taint step that involves promises.
*/
private class PromiseTaintStep extends TaintTracking::AdditionalTaintStep {
DataFlow::Node source;
PromiseTaintStep() { promiseTaintStep(source, this) }
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = source and succ = this
}
}
/**
* A flow step propagating the exception thrown from a callback to a method whose name coincides
* a built-in Array iteration method, such as `forEach` or `map`.
@@ -298,9 +113,7 @@ class StringReplaceCall extends DataFlow::MethodCallNode {
}
/** Gets the regular expression passed as the first argument to `replace`, if any. */
DataFlow::RegExpLiteralNode getRegExp() {
result.flowsTo(getArgument(0))
}
DataFlow::RegExpLiteralNode getRegExp() { result.flowsTo(getArgument(0)) }
/** Gets a string that is being replaced by this call. */
string getAReplacedString() {
@@ -312,17 +125,13 @@ class StringReplaceCall extends DataFlow::MethodCallNode {
* Gets the second argument of this call to `replace`, which is either a string
* or a callback.
*/
DataFlow::Node getRawReplacement() {
result = getArgument(1)
}
DataFlow::Node getRawReplacement() { result = getArgument(1) }
/**
* Holds if this is a global replacement, that is, the first argument is a regular expression
* with the `g` flag.
*/
predicate isGlobal() {
getRegExp().isGlobal()
}
predicate isGlobal() { getRegExp().isGlobal() }
/**
* Holds if this call to `replace` replaces `old` with `new`.

View File

@@ -23,11 +23,11 @@
| partial.js:5:15:5:24 | "tainted1" | partial.js:21:15:21:15 | x |
| partial.js:5:15:5:24 | "tainted1" | partial.js:27:15:27:15 | x |
| promises.js:2:16:2:24 | "tainted" | promises.js:7:16:7:18 | val |
| promises.js:2:16:2:24 | "tainted" | promises.js:38:32:38:32 | v |
| promises.js:11:22:11:31 | "resolved" | promises.js:19:20:19:20 | v |
| promises.js:11:22:11:31 | "resolved" | promises.js:27:16:27:16 | v |
| promises.js:12:22:12:31 | "rejected" | promises.js:21:20:21:20 | v |
| promises.js:12:22:12:31 | "rejected" | promises.js:24:20:24:20 | v |
| promises.js:12:22:12:31 | "rejected" | promises.js:27:16:27:16 | v |
| promises.js:32:24:32:37 | "also tainted" | promises.js:38:32:38:32 | v |
| properties2.js:7:14:7:21 | "source" | properties2.js:8:12:8:24 | foo(source).p |
| properties2.js:7:14:7:21 | "source" | properties2.js:33:13:33:20 | getP(o3) |
| properties.js:2:16:2:24 | "tainted" | properties.js:5:14:5:23 | a.someProp |

View File

@@ -30,10 +30,8 @@
| promises.js:2:16:2:24 | "tainted" | promises.js:7:16:7:18 | val |
| promises.js:2:16:2:24 | "tainted" | promises.js:38:32:38:32 | v |
| promises.js:11:22:11:31 | "resolved" | promises.js:19:20:19:20 | v |
| promises.js:11:22:11:31 | "resolved" | promises.js:27:16:27:16 | v |
| promises.js:12:22:12:31 | "rejected" | promises.js:21:20:21:20 | v |
| promises.js:12:22:12:31 | "rejected" | promises.js:24:20:24:20 | v |
| promises.js:12:22:12:31 | "rejected" | promises.js:27:16:27:16 | v |
| promises.js:32:24:32:37 | "also tainted" | promises.js:38:32:38:32 | v |
| properties2.js:7:14:7:21 | "source" | properties2.js:8:12:8:24 | foo(source).p |
| properties2.js:7:14:7:21 | "source" | properties2.js:33:13:33:20 | getP(o3) |

View File

@@ -23,7 +23,7 @@
promise2.catch((v) => {
var rej_sink = v;
});
promise2.finally((v) => {
promise2.finally((v) => { // no promise implementation sends an argument to the finally handler. So there is no data-flow here.
var sink = v;
});

View File

@@ -0,0 +1,5 @@
import javascript
query predicate flowSteps(DataFlow::Node pred, DataFlow::Node succ) {
any(DataFlow::AdditionalFlowStep step).step(pred, succ)
}

View File

@@ -0,0 +1,56 @@
(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();
})();

View File

@@ -1,12 +1,27 @@
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 |
| 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) |
| 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 } |
| 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 } |
@@ -14,25 +29,103 @@ 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 }) |
| 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 |
| 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 |
| 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 |
| 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) |
| 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 |

View File

@@ -7,3 +7,4 @@ import PromiseDefinition_getAResolveHandler
import PromiseDefinition_getRejectParameter
import PromiseDefinition_getResolveParameter
import PromiseDefinition_getACatchHandler
import Flowsteps