mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Merge pull request #2618 from erik-krogh/ExceptionalPromise
Approved by asgerf
This commit is contained in:
@@ -1,9 +1,385 @@
|
||||
/**
|
||||
* 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 of a Promise.
|
||||
* The data-flow is based on pseudo-properties rather than tainting the Promise object (which is what `PromiseTaintStep` does).
|
||||
*/
|
||||
private module PromiseFlow {
|
||||
/**
|
||||
* Gets the pseudo-field used to describe resolved values in a promise.
|
||||
*/
|
||||
string resolveField() {
|
||||
result = "$PromiseResolveField$"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pseudo-field used to describe rejected values in a promise.
|
||||
*/
|
||||
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;
|
||||
PromiseDefitionStep() {
|
||||
this = promise
|
||||
}
|
||||
|
||||
override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
pred = promise.getResolveParameter().getACall().getArgument(0) and
|
||||
succ = this
|
||||
or
|
||||
prop = rejectField() and
|
||||
(
|
||||
pred = promise.getRejectParameter().getACall().getArgument(0) or
|
||||
pred = promise.getExecutor().getExceptionalReturn()
|
||||
) and
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
// Copy the value of a resolved promise to the value of this promise.
|
||||
prop = resolveField() and
|
||||
pred = promise.getResolveParameter().getACall().getArgument(0) and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow step describing the a Promise.resolve (and similar) call.
|
||||
*/
|
||||
class CreationStep extends DataFlow::AdditionalFlowStep {
|
||||
PromiseCreationCall promise;
|
||||
CreationStep() {
|
||||
this = promise
|
||||
}
|
||||
|
||||
override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
pred = promise.getValue() and
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
// Copy the value of a resolved promise to the value of this promise.
|
||||
prop = resolveField() and
|
||||
pred = promise.getValue() and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A load step loading the pseudo-field describing that the promise is rejected.
|
||||
* The rejected value is thrown as a exception.
|
||||
*/
|
||||
class AwaitStep extends DataFlow::AdditionalFlowStep {
|
||||
DataFlow::Node operand;
|
||||
AwaitExpr await;
|
||||
AwaitStep() {
|
||||
this.getEnclosingExpr() = await and
|
||||
operand.getEnclosingExpr() = await.getOperand()
|
||||
}
|
||||
|
||||
override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
succ = this and
|
||||
pred = operand
|
||||
or
|
||||
prop = rejectField() and
|
||||
succ = await.getExceptionTarget() and
|
||||
pred = operand
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
pred = getReceiver() and
|
||||
succ = getCallback(0).getParameter(0)
|
||||
or
|
||||
prop = rejectField() and
|
||||
pred = getReceiver() and
|
||||
succ = getCallback(1).getParameter(0)
|
||||
}
|
||||
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
not exists(this.getArgument(1)) and
|
||||
prop = rejectField() and
|
||||
pred = getReceiver() and
|
||||
succ = this
|
||||
or
|
||||
// read the value of a resolved/rejected promise that is returned
|
||||
(prop = rejectField() or prop = resolveField()) and
|
||||
pred = getCallback([0..1]).getAReturn() and
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate storeStep(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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow step describing the data-flow related to the `.catch` method of a promise.
|
||||
*/
|
||||
class CatchStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
|
||||
CatchStep() {
|
||||
this.getMethodName() = "catch"
|
||||
}
|
||||
|
||||
override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = rejectField() and
|
||||
pred = getReceiver() and
|
||||
succ = getCallback(0).getParameter(0)
|
||||
}
|
||||
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = resolveField() and
|
||||
pred = getReceiver().getALocalSource() and
|
||||
succ = this
|
||||
or
|
||||
// read the value of a resolved/rejected promise that is returned
|
||||
(prop = rejectField() or prop = resolveField()) and
|
||||
pred = getCallback(0).getAReturn() and
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = rejectField() and
|
||||
pred = getCallback(0).getExceptionalReturn() and
|
||||
succ = this
|
||||
or
|
||||
prop = resolveField() and
|
||||
pred = getCallback(0).getAReturn() and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow step describing the data-flow related to the `.finally` method of a promise.
|
||||
*/
|
||||
class FinallyStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
|
||||
FinallyStep() {
|
||||
this.getMethodName() = "finally"
|
||||
}
|
||||
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
(prop = resolveField() or prop = rejectField()) and
|
||||
pred = getReceiver() and
|
||||
succ = this
|
||||
or
|
||||
// read the value of a rejected promise that is returned
|
||||
prop = rejectField() and
|
||||
pred = getCallback(0).getAReturn() and
|
||||
succ = this
|
||||
}
|
||||
|
||||
override predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
prop = rejectField() and
|
||||
pred = getCallback(0).getExceptionalReturn() and
|
||||
succ = this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 |
|
||||
thn.getMethodName() = "then"
|
||||
|
|
||||
// from `p` to `x` in `p.then(x => ...)`
|
||||
pred = thn.getReceiver() and
|
||||
succ = thn.getCallback(0).getParameter(0)
|
||||
or
|
||||
// from `v` to `p.then(x => return v)`
|
||||
pred = thn.getCallback([0..1]).getAReturn() and
|
||||
succ = thn
|
||||
)
|
||||
or
|
||||
exists(DataFlow::MethodCallNode catch | catch.getMethodName() = "catch" |
|
||||
// from `p` to `p.catch(..)`
|
||||
pred = catch.getReceiver() and
|
||||
succ = catch
|
||||
or
|
||||
// from `v` to `p.catch(x => return v)`
|
||||
pred = catch.getCallback(0).getAReturn() and
|
||||
succ = catch
|
||||
)
|
||||
or
|
||||
// from `p` to `p.finally(..)`
|
||||
exists(DataFlow::MethodCallNode finally | finally.getMethodName() = "finally" |
|
||||
pred = finally.getReceiver() and
|
||||
succ = finally
|
||||
)
|
||||
or
|
||||
// from `x` to `await x`
|
||||
exists(AwaitExpr await |
|
||||
pred.getEnclosingExpr() = await.getOperand() and
|
||||
succ.getEnclosingExpr() = await
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -223,6 +223,29 @@ abstract class Configuration extends string {
|
||||
predicate hasFlowPath(SourcePathNode source, SinkPathNode sink) {
|
||||
flowsTo(source, _, sink, _, this)
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
*/
|
||||
predicate isAdditionalStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* 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() }
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
|
||||
*/
|
||||
predicate isAdditionalLoadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,11 +330,8 @@ abstract class BarrierGuardNode extends DataFlow::Node {
|
||||
// 1) `nd` is a use of a refinement node that blocks its input variable
|
||||
exists(SsaRefinementNode ref, boolean outcome |
|
||||
nd = DataFlow::ssaDefinitionNode(ref) and
|
||||
forex(SsaVariable input | input = ref.getAnInput() |
|
||||
getEnclosingExpr() = ref.getGuard().getTest() and
|
||||
outcome = ref.getGuard().(ConditionGuardNode).getOutcome() and
|
||||
barrierGuardBlocksExpr(this, outcome, input.getAUse(), label)
|
||||
)
|
||||
outcome = ref.getGuard().(ConditionGuardNode).getOutcome() and
|
||||
ssaRefinementBlocks(outcome, ref, label)
|
||||
)
|
||||
or
|
||||
// 2) `nd` is an instance of an access path `p`, and dominated by a barrier for `p`
|
||||
@@ -324,6 +344,18 @@ abstract class BarrierGuardNode extends DataFlow::Node {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists an input variable of `ref` that blocks the label `label`.
|
||||
*
|
||||
* This predicate is outlined to give the optimizer a hint about the join ordering.
|
||||
*/
|
||||
private predicate ssaRefinementBlocks(boolean outcome, SsaRefinementNode ref, string label) {
|
||||
getEnclosingExpr() = ref.getGuard().getTest() and
|
||||
forex(SsaVariable input | input = ref.getAnInput() |
|
||||
barrierGuardBlocksExpr(this, outcome, input.getAUse(), label)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node blocks expression `e` provided it evaluates to `outcome`.
|
||||
*
|
||||
@@ -338,11 +370,13 @@ abstract class BarrierGuardNode extends DataFlow::Node {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow node `nd` acts as a barrier for data flow.
|
||||
*
|
||||
* `label` is bound to the blocked label, or the empty string if all labels should be blocked.
|
||||
*/
|
||||
private predicate barrierGuardBlocksExpr(BarrierGuardNode guard, boolean outcome, Expr test, string label) {
|
||||
* Holds if data flow node `nd` acts as a barrier for data flow.
|
||||
*
|
||||
* `label` is bound to the blocked label, or the empty string if all labels should be blocked.
|
||||
*/
|
||||
private predicate barrierGuardBlocksExpr(
|
||||
BarrierGuardNode guard, boolean outcome, Expr test, string label
|
||||
) {
|
||||
guard.blocks(outcome, test) and label = ""
|
||||
or
|
||||
guard.blocks(outcome, test, label)
|
||||
@@ -353,23 +387,29 @@ private predicate barrierGuardBlocksExpr(BarrierGuardNode guard, boolean outcome
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow node `nd` acts as a barrier for data flow due to aliasing through
|
||||
* an access path.
|
||||
*
|
||||
* `label` is bound to the blocked label, or the empty string if all labels should be blocked.
|
||||
*/
|
||||
* Holds if data flow node `nd` acts as a barrier for data flow due to aliasing through
|
||||
* an access path.
|
||||
*
|
||||
* `label` is bound to the blocked label, or the empty string if all labels should be blocked.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate barrierGuardBlocksAccessPath(BarrierGuardNode guard, boolean outcome, AccessPath ap, string label) {
|
||||
private predicate barrierGuardBlocksAccessPath(
|
||||
BarrierGuardNode guard, boolean outcome, AccessPath ap, string label
|
||||
) {
|
||||
barrierGuardBlocksExpr(guard, outcome, ap.getAnInstance(), label)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `guard` should block flow along the edge `pred -> succ`.
|
||||
*
|
||||
* `label` is bound to the blocked label, or the empty string if all labels should be blocked.
|
||||
*/
|
||||
private predicate barrierGuardBlocksEdge(BarrierGuardNode guard, DataFlow::Node pred, DataFlow::Node succ, string label) {
|
||||
exists(SsaVariable input, SsaPhiNode phi, BasicBlock bb, ConditionGuardNode cond, boolean outcome |
|
||||
* Holds if `guard` should block flow along the edge `pred -> succ`.
|
||||
*
|
||||
* `label` is bound to the blocked label, or the empty string if all labels should be blocked.
|
||||
*/
|
||||
private predicate barrierGuardBlocksEdge(
|
||||
BarrierGuardNode guard, DataFlow::Node pred, DataFlow::Node succ, string label
|
||||
) {
|
||||
exists(
|
||||
SsaVariable input, SsaPhiNode phi, BasicBlock bb, ConditionGuardNode cond, boolean outcome
|
||||
|
|
||||
pred = DataFlow::ssaDefinitionNode(input) and
|
||||
succ = DataFlow::ssaDefinitionNode(phi) and
|
||||
input = phi.getInputFromBlock(bb) and
|
||||
@@ -399,7 +439,9 @@ private predicate isBarrierEdge(Configuration cfg, DataFlow::Node pred, DataFlow
|
||||
* Holds if there is a labeled barrier edge `pred -> succ` in `cfg` either through an explicit barrier edge
|
||||
* or one implied by a barrier guard.
|
||||
*/
|
||||
private predicate isLabeledBarrierEdge(Configuration cfg, DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel label) {
|
||||
private predicate isLabeledBarrierEdge(
|
||||
Configuration cfg, DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel label
|
||||
) {
|
||||
cfg.isBarrierEdge(pred, succ, label)
|
||||
or
|
||||
exists(DataFlow::BarrierGuardNode guard |
|
||||
@@ -449,6 +491,30 @@ abstract class AdditionalFlowStep extends DataFlow::Node {
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
*/
|
||||
cached
|
||||
predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
|
||||
*/
|
||||
cached
|
||||
predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL. This API may change in the future.
|
||||
*
|
||||
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
|
||||
*/
|
||||
cached
|
||||
predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -551,6 +617,9 @@ private predicate exploratoryFlowStep(
|
||||
basicFlowStep(pred, succ, _, cfg) or
|
||||
basicStoreStep(pred, succ, _) or
|
||||
basicLoadStep(pred, succ, _) or
|
||||
isAdditionalStoreStep(pred, succ, _, cfg) or
|
||||
isAdditionalLoadStep(pred, succ, _, cfg) or
|
||||
isAdditionalLoadStoreStep(pred, succ, _, cfg) or
|
||||
// the following two disjuncts taken together over-approximate flow through
|
||||
// higher-order calls
|
||||
callback(pred, succ) or
|
||||
@@ -712,6 +781,9 @@ private predicate storeStep(
|
||||
basicStoreStep(pred, succ, prop) and
|
||||
summary = PathSummary::level()
|
||||
or
|
||||
isAdditionalStoreStep(pred, succ, prop, cfg) 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`
|
||||
@@ -719,6 +791,10 @@ private predicate storeStep(
|
||||
(
|
||||
returnedPropWrite(f, _, prop, mid)
|
||||
or
|
||||
exists(DataFlow::SourceNode base | base.flowsToExpr(f.getAReturnedExpr()) |
|
||||
isAdditionalStoreStep(mid, base, prop, cfg)
|
||||
)
|
||||
or
|
||||
succ instanceof DataFlow::NewNode and
|
||||
receiverPropWrite(f, prop, mid)
|
||||
)
|
||||
@@ -729,12 +805,16 @@ private predicate storeStep(
|
||||
* Holds if `f` may `read` property `prop` of parameter `parm`.
|
||||
*/
|
||||
private predicate parameterPropRead(
|
||||
Function f, DataFlow::Node invk, DataFlow::Node arg, string prop, DataFlow::PropRead read,
|
||||
Function f, DataFlow::Node invk, DataFlow::Node arg, string prop, DataFlow::Node read,
|
||||
DataFlow::Configuration cfg
|
||||
) {
|
||||
exists(DataFlow::SourceNode parm |
|
||||
callInputStep(f, invk, arg, parm, cfg) and
|
||||
read = parm.getAPropertyRead(prop)
|
||||
(
|
||||
read = parm.getAPropertyRead(prop)
|
||||
or
|
||||
exists(DataFlow::Node use | parm.flowsTo(use) | isAdditionalLoadStep(use, read, prop, cfg))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -756,6 +836,39 @@ private predicate reachesReturn(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
|
||||
*/
|
||||
private predicate isAdditionalLoadStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string prop, DataFlow::Configuration cfg
|
||||
) {
|
||||
any(AdditionalFlowStep s).loadStep(pred, succ, prop)
|
||||
or
|
||||
cfg.isAdditionalLoadStep(pred, succ, prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
|
||||
*/
|
||||
private predicate isAdditionalStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string prop, DataFlow::Configuration cfg
|
||||
) {
|
||||
any(AdditionalFlowStep s).storeStep(pred, succ, prop)
|
||||
or
|
||||
cfg.isAdditionalStoreStep(pred, succ, prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
|
||||
*/
|
||||
private predicate isAdditionalLoadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string prop, DataFlow::Configuration cfg
|
||||
) {
|
||||
any(AdditionalFlowStep s).loadStoreStep(pred, succ, prop)
|
||||
or
|
||||
cfg.isAdditionalLoadStoreStep(pred, succ, prop)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if property `prop` of `pred` may flow into `succ` along a path summarized by
|
||||
* `summary`.
|
||||
@@ -767,7 +880,10 @@ private predicate loadStep(
|
||||
basicLoadStep(pred, succ, prop) and
|
||||
summary = PathSummary::level()
|
||||
or
|
||||
exists(Function f, DataFlow::PropRead read |
|
||||
isAdditionalLoadStep(pred, succ, prop, cfg) and
|
||||
summary = PathSummary::level()
|
||||
or
|
||||
exists(Function f, DataFlow::Node read |
|
||||
parameterPropRead(f, succ, pred, prop, read, cfg) and
|
||||
reachesReturn(f, read, cfg, summary)
|
||||
)
|
||||
@@ -788,7 +904,12 @@ private predicate reachableFromStoreBase(
|
||||
or
|
||||
exists(DataFlow::Node mid, PathSummary oldSummary, PathSummary newSummary |
|
||||
reachableFromStoreBase(prop, rhs, mid, cfg, oldSummary) and
|
||||
flowStep(mid, cfg, nd, newSummary) and
|
||||
(
|
||||
flowStep(mid, cfg, nd, newSummary)
|
||||
or
|
||||
isAdditionalLoadStoreStep(mid, nd, prop, cfg) and
|
||||
newSummary = PathSummary::level()
|
||||
) and
|
||||
summary = oldSummary.appendValuePreserving(newSummary)
|
||||
)
|
||||
}
|
||||
@@ -996,19 +1117,19 @@ private predicate onPath(DataFlow::Node nd, DataFlow::Configuration cfg, PathSum
|
||||
* Holds if there is a configuration that has at least one source and at least one sink.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate isLive() { exists(DataFlow::Configuration cfg | isSource(_, cfg, _) and isSink(_, cfg, _)) }
|
||||
private predicate isLive() {
|
||||
exists(DataFlow::Configuration cfg | isSource(_, cfg, _) and isSink(_, cfg, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node on an inter-procedural path from a source.
|
||||
*/
|
||||
private newtype TPathNode =
|
||||
MkSourceNode(DataFlow::Node nd, DataFlow::Configuration cfg) { isSourceNode(nd, cfg, _) }
|
||||
or
|
||||
MkSourceNode(DataFlow::Node nd, DataFlow::Configuration cfg) { isSourceNode(nd, cfg, _) } or
|
||||
MkMidNode(DataFlow::Node nd, DataFlow::Configuration cfg, PathSummary summary) {
|
||||
isLive() and
|
||||
onPath(nd, cfg, summary)
|
||||
}
|
||||
or
|
||||
} or
|
||||
MkSinkNode(DataFlow::Node nd, DataFlow::Configuration cfg) { isSinkNode(nd, cfg, _) }
|
||||
|
||||
/**
|
||||
@@ -1069,9 +1190,7 @@ class PathNode extends TPathNode {
|
||||
}
|
||||
|
||||
/** Holds if this path node wraps data-flow node `nd` and configuration `c`. */
|
||||
predicate wraps(DataFlow::Node n, DataFlow::Configuration c) {
|
||||
nd = n and cfg = c
|
||||
}
|
||||
predicate wraps(DataFlow::Node n, DataFlow::Configuration c) { nd = n and cfg = c }
|
||||
|
||||
/** Gets the underlying configuration of this path node. */
|
||||
DataFlow::Configuration getConfiguration() { result = cfg }
|
||||
@@ -1080,9 +1199,7 @@ class PathNode extends TPathNode {
|
||||
DataFlow::Node getNode() { result = nd }
|
||||
|
||||
/** Gets a successor node of this path node. */
|
||||
final PathNode getASuccessor() {
|
||||
result = getASuccessor(this)
|
||||
}
|
||||
final PathNode getASuccessor() { result = getASuccessor(this) }
|
||||
|
||||
/** Gets a textual representation of this path node. */
|
||||
string toString() { result = nd.toString() }
|
||||
@@ -1126,7 +1243,10 @@ private MidPathNode finalMidNode(SinkPathNode snk) {
|
||||
* This helper predicate exists to clarify the intended join order in `getASuccessor` below.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate midNodeStep(PathNode nd, DataFlow::Node predNd, Configuration cfg, PathSummary summary, DataFlow::Node succNd, PathSummary newSummary) {
|
||||
private predicate midNodeStep(
|
||||
PathNode nd, DataFlow::Node predNd, Configuration cfg, PathSummary summary, DataFlow::Node succNd,
|
||||
PathSummary newSummary
|
||||
) {
|
||||
nd = MkMidNode(predNd, cfg, summary) and
|
||||
flowStep(predNd, id(cfg), succNd, newSummary)
|
||||
}
|
||||
@@ -1139,7 +1259,10 @@ private PathNode getASuccessor(PathNode nd) {
|
||||
result = initialMidNode(nd)
|
||||
or
|
||||
// mid node to mid node
|
||||
exists(Configuration cfg, DataFlow::Node predNd, PathSummary summary, DataFlow::Node succNd, PathSummary newSummary |
|
||||
exists(
|
||||
Configuration cfg, DataFlow::Node predNd, PathSummary summary, DataFlow::Node succNd,
|
||||
PathSummary newSummary
|
||||
|
|
||||
midNodeStep(nd, predNd, cfg, summary, succNd, newSummary) and
|
||||
result = MkMidNode(succNd, id(cfg), summary.append(newSummary))
|
||||
)
|
||||
@@ -1210,9 +1333,7 @@ class SinkPathNode extends PathNode, MkSinkNode {
|
||||
*/
|
||||
module PathGraph {
|
||||
/** Holds if `nd` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode nd) {
|
||||
not nd.(MidPathNode).isHidden()
|
||||
}
|
||||
query predicate nodes(PathNode nd) { not nd.(MidPathNode).isHidden() }
|
||||
|
||||
/**
|
||||
* Gets a node to which data from `nd` may flow in one step, skipping over hidden nodes.
|
||||
@@ -1220,7 +1341,8 @@ module PathGraph {
|
||||
private PathNode succ0(PathNode nd) {
|
||||
result = getASuccessorIfHidden*(nd.getASuccessor()) and
|
||||
// skip hidden nodes
|
||||
nodes(nd) and nodes(result)
|
||||
nodes(nd) and
|
||||
nodes(result)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1260,27 +1382,21 @@ module PathGraph {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets an operand of the given `&&` operator.
|
||||
*
|
||||
* We use this to construct the transitive closure over a relation
|
||||
* that does not include all of `BinaryExpr.getAnOperand`.
|
||||
*/
|
||||
private Expr getALogicalAndOperand(LogAndExpr e) { result = e.getAnOperand() }
|
||||
|
||||
/**
|
||||
* Gets an operand of the given `&&` operator.
|
||||
*
|
||||
* We use this to construct the transitive closure over a relation
|
||||
* that does not include all of `BinaryExpr.getAnOperand`.
|
||||
*/
|
||||
private Expr getALogicalAndOperand(LogAndExpr e) {
|
||||
result = e.getAnOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an operand of the given `||` operator.
|
||||
*
|
||||
* We use this to construct the transitive closure over a relation
|
||||
* that does not include all of `BinaryExpr.getAnOperand`.
|
||||
*/
|
||||
private Expr getALogicalOrOperand(LogOrExpr e) {
|
||||
result = e.getAnOperand()
|
||||
}
|
||||
* Gets an operand of the given `||` operator.
|
||||
*
|
||||
* We use this to construct the transitive closure over a relation
|
||||
* that does not include all of `BinaryExpr.getAnOperand`.
|
||||
*/
|
||||
private Expr getALogicalOrOperand(LogOrExpr e) { result = e.getAnOperand() }
|
||||
|
||||
/**
|
||||
* A `BarrierGuardNode` that controls which data flow
|
||||
@@ -1295,8 +1411,8 @@ abstract class AdditionalBarrierGuardNode extends BarrierGuardNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that returns the result of a barrier guard.
|
||||
*/
|
||||
* A function that returns the result of a barrier guard.
|
||||
*/
|
||||
private class BarrierGuardFunction extends Function {
|
||||
DataFlow::ParameterNode sanitizedParameter;
|
||||
BarrierGuardNode guard;
|
||||
@@ -1329,8 +1445,8 @@ private class BarrierGuardFunction extends Function {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this function sanitizes argument `e` of call `call`, provided the call evaluates to `outcome`.
|
||||
*/
|
||||
* Holds if this function sanitizes argument `e` of call `call`, provided the call evaluates to `outcome`.
|
||||
*/
|
||||
predicate isBarrierCall(DataFlow::CallNode call, Expr e, boolean outcome, string lbl) {
|
||||
exists(DataFlow::Node arg |
|
||||
arg.asExpr() = e and
|
||||
@@ -1343,22 +1459,20 @@ private class BarrierGuardFunction extends Function {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this function applies to the flow in `cfg`.
|
||||
*/
|
||||
* Holds if this function applies to the flow in `cfg`.
|
||||
*/
|
||||
predicate appliesTo(Configuration cfg) { cfg.isBarrierGuard(guard) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call that sanitizes an argument.
|
||||
*/
|
||||
* A call that sanitizes an argument.
|
||||
*/
|
||||
private class AdditionalBarrierGuardCall extends AdditionalBarrierGuardNode, DataFlow::CallNode {
|
||||
BarrierGuardFunction f;
|
||||
|
||||
AdditionalBarrierGuardCall() { f.isBarrierCall(this, _, _, _) }
|
||||
|
||||
override predicate blocks(boolean outcome, Expr e) {
|
||||
f.isBarrierCall(this, e, outcome, "")
|
||||
}
|
||||
override predicate blocks(boolean outcome, Expr e) { f.isBarrierCall(this, e, outcome, "") }
|
||||
|
||||
predicate internalBlocksLabel(boolean outcome, Expr e, DataFlow::FlowLabel label) {
|
||||
f.isBarrierCall(this, e, outcome, label)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
| tst.js:4:15:4:22 | "source" | tst.js:9:7:9:24 | readTaint(tainted) |
|
||||
@@ -0,0 +1,26 @@
|
||||
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
|
||||
}
|
||||
|
||||
// When the source code states that "foo" is being read, "bar" is additionally being read.
|
||||
override predicate isAdditionalLoadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
exists(DataFlow::PropRead read | read = succ |
|
||||
read.getBase() = pred and
|
||||
read.getPropertyName() = "foo"
|
||||
) and
|
||||
prop = "bar"
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::Node pred, DataFlow::Node succ, Configuration cfg
|
||||
where cfg.hasFlow(pred, succ)
|
||||
select pred, succ
|
||||
10
javascript/ql/test/library-tests/CustomLoadStoreSteps/tst.js
Normal file
10
javascript/ql/test/library-tests/CustomLoadStoreSteps/tst.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// When the source code states that "foo" is being read, "bar" is additionally being read.
|
||||
|
||||
(function () {
|
||||
var source = "source";
|
||||
var tainted = { bar: source };
|
||||
function readTaint(x) {
|
||||
return x.foo;
|
||||
}
|
||||
sink(readTaint(tainted));
|
||||
})();
|
||||
@@ -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 |
|
||||
|
||||
@@ -24,11 +24,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 |
|
||||
|
||||
@@ -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) |
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
| missing | promises.js:1:2:1:2 | source | promises.js:6:26:6:28 | val |
|
||||
| missing | promises.js:1:2:1:2 | source | promises.js:7:16:7:18 | val |
|
||||
| missing | promises.js:1:2:1:2 | source | promises.js:37:11:37:11 | v |
|
||||
| missing | promises.js:1:2:1:2 | source | promises.js:38:32:38:32 | v |
|
||||
| missing | promises.js:2:16:2:24 | "tainted" | promises.js:6:26:6:28 | val |
|
||||
| missing | promises.js:2:16:2:24 | "tainted" | promises.js:7:16:7:18 | val |
|
||||
| missing | promises.js:2:16:2:24 | "tainted" | promises.js:37:11:37:11 | v |
|
||||
| missing | promises.js:2:16:2:24 | "tainted" | promises.js:38:32:38:32 | v |
|
||||
| missing | promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:20:7:20:7 | v |
|
||||
| missing | promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:21:20:21:20 | v |
|
||||
| missing | promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:23:19:23:19 | v |
|
||||
| missing | promises.js:10:30:17:3 | exceptional return of anonymous function | promises.js:24:20:24:20 | v |
|
||||
| missing | promises.js:11:22:11:31 | "resolved" | promises.js:18:18:18:18 | v |
|
||||
| missing | promises.js:11:22:11:31 | "resolved" | promises.js:19:20:19:20 | v |
|
||||
| missing | promises.js:12:22:12:31 | "rejected" | promises.js:20:7:20:7 | v |
|
||||
| missing | promises.js:12:22:12:31 | "rejected" | promises.js:21:20:21:20 | v |
|
||||
| missing | promises.js:12:22:12:31 | "rejected" | promises.js:23:19:23:19 | v |
|
||||
| missing | promises.js:12:22:12:31 | "rejected" | promises.js:24:20:24:20 | v |
|
||||
| missing | promises.js:13:9:13:21 | exceptional return of Math.random() | promises.js:20:7:20:7 | v |
|
||||
| missing | promises.js:13:9:13:21 | exceptional return of Math.random() | promises.js:21:20:21:20 | v |
|
||||
| missing | promises.js:13:9:13:21 | exceptional return of Math.random() | promises.js:23:19:23:19 | v |
|
||||
| missing | promises.js:13:9:13:21 | exceptional return of Math.random() | promises.js:24:20:24:20 | v |
|
||||
| missing | promises.js:14:7:14:21 | exceptional return of res(res_source) | promises.js:20:7:20:7 | v |
|
||||
| missing | promises.js:14:7:14:21 | exceptional return of res(res_source) | promises.js:21:20:21:20 | v |
|
||||
| missing | promises.js:14:7:14:21 | exceptional return of res(res_source) | promises.js:23:19:23:19 | v |
|
||||
| missing | promises.js:14:7:14:21 | exceptional return of res(res_source) | promises.js:24:20:24:20 | v |
|
||||
| missing | promises.js:16:7:16:21 | exceptional return of rej(rej_source) | promises.js:20:7:20:7 | v |
|
||||
| missing | promises.js:16:7:16:21 | exceptional return of rej(rej_source) | promises.js:21:20:21:20 | v |
|
||||
| missing | promises.js:16:7:16:21 | exceptional return of rej(rej_source) | promises.js:23:19:23:19 | v |
|
||||
| missing | promises.js:16:7:16:21 | exceptional return of rej(rej_source) | promises.js:24:20:24:20 | v |
|
||||
| missing | promises.js:32:24:32:37 | "also tainted" | promises.js:37:11:37:11 | v |
|
||||
| missing | promises.js:32:24:32:37 | "also tainted" | promises.js:38:32:38:32 | v |
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,74 @@
|
||||
| additional-promises.js:2:13:2:57 | new Pin ... ct) {}) |
|
||||
| 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:20:2:20:24 | Promise ... source) |
|
||||
| flow.js:22:2:22:24 | Promise ... source) |
|
||||
| flow.js:24:2:24:49 | new Pro ... ource)) |
|
||||
| flow.js:26:2:26:49 | new Pro ... ource)) |
|
||||
| flow.js:28:2:28:23 | Promise ... ("foo") |
|
||||
| flow.js:28:2:28:41 | Promise ... source) |
|
||||
| flow.js:30:2:30:24 | Promise ... source) |
|
||||
| flow.js:30:2:30:41 | Promise ... "foo") |
|
||||
| flow.js:32:2:32:49 | new Pro ... ource)) |
|
||||
| flow.js:34:2:34:24 | Promise ... source) |
|
||||
| flow.js:34:2:34:41 | Promise ... => { }) |
|
||||
| flow.js:36:11:36:33 | Promise ... source) |
|
||||
| flow.js:37:11:37:29 | p5.catch(() => { }) |
|
||||
| flow.js:40:2:40:49 | new Pro ... ource)) |
|
||||
| flow.js:40:2:40:65 | new Pro ... => { }) |
|
||||
| flow.js:42:2:42:49 | new Pro ... ource)) |
|
||||
| flow.js:42:2:42:76 | new Pro ... => { }) |
|
||||
| flow.js:44:2:44:24 | Promise ... source) |
|
||||
| flow.js:44:2:44:41 | Promise ... => { }) |
|
||||
| flow.js:44:2:44:58 | Promise ... => { }) |
|
||||
| flow.js:44:2:44:75 | Promise ... => { }) |
|
||||
| flow.js:46:2:46:24 | Promise ... source) |
|
||||
| flow.js:46:2:46:43 | Promise ... => { }) |
|
||||
| flow.js:48:2:48:36 | new Pro ... urce }) |
|
||||
| flow.js:53:2:53:22 | createP ... source) |
|
||||
| flow.js:55:11:55:58 | new Pro ... ource)) |
|
||||
| flow.js:56:11:56:27 | p8.then(() => {}) |
|
||||
| flow.js:57:12:57:31 | p9.finally(() => {}) |
|
||||
| flow.js:60:12:60:59 | new Pro ... ource)) |
|
||||
| flow.js:61:12:61:29 | p11.then(() => {}) |
|
||||
| flow.js:65:9:65:56 | new Pro ... ource)) |
|
||||
| flow.js:74:10:74:57 | new Pro ... ource)) |
|
||||
| flow.js:76:2:76:17 | chainedPromise() |
|
||||
| flow.js:76:2:76:32 | chained ... => {}) |
|
||||
| flow.js:86:23:86:70 | new Pro ... ource)) |
|
||||
| flow.js:89:3:89:27 | ("foo", ... => {}) |
|
||||
| flow.js:91:21:91:68 | new Pro ... ource)) |
|
||||
| flow.js:100:28:100:75 | new Pro ... ource)) |
|
||||
| flow.js:103:2:103:48 | new Pro ... "BLA")) |
|
||||
| flow.js:103:2:103:76 | new Pro ... ource}) |
|
||||
| flow.js:105:2:105:48 | new Pro ... "BLA")) |
|
||||
| flow.js:105:2:105:77 | new Pro ... ource}) |
|
||||
| flow.js:107:17:107:64 | new Pro ... ource)) |
|
||||
| flow.js:109:2:109:48 | new Pro ... "BLA")) |
|
||||
| flow.js:109:2:109:71 | new Pro ... jected) |
|
||||
| flow.js:111:2:111:48 | new Pro ... "BLA")) |
|
||||
| flow.js:111:2:111:69 | new Pro ... jected) |
|
||||
| flow.js:113:2:113:48 | new Pro ... "BLA")) |
|
||||
| flow.js:113:2:113:69 | new Pro ... jected) |
|
||||
| flow.js:117:2:117:48 | new Pro ... "BLA")) |
|
||||
| flow.js:117:2:117:69 | new Pro ... solved) |
|
||||
| flow.js:119:2:119:48 | new Pro ... "BLA")) |
|
||||
| flow.js:119:2:119:69 | new Pro ... solved) |
|
||||
| flow.js:121:2:121:21 | Promise.resolve(123) |
|
||||
| flow.js:121:2:121:41 | Promise ... solved) |
|
||||
| flow.js:123:2:123:21 | Promise.resolve(123) |
|
||||
| flow.js:123:2:123:41 | Promise ... solved) |
|
||||
| flow.js:125:2:125:21 | Promise.resolve(123) |
|
||||
| flow.js:125:2:125:41 | Promise ... jected) |
|
||||
| flow.js:127:2:127:21 | Promise.resolve(123) |
|
||||
| flow.js:127:2:127:41 | Promise ... jected) |
|
||||
| flow.js:129:2:129:52 | new Pro ... olved)) |
|
||||
| flow.js:131:2:131:26 | Promise ... solved) |
|
||||
| interflow.js:6:3:6:25 | loadScr ... urce()) |
|
||||
| interflow.js:6:3:7:26 | loadScr ... () { }) |
|
||||
| interflow.js:6:3:8:26 | loadScr ... () { }) |
|
||||
| interflow.js:11:12:15:6 | 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 }) |
|
||||
|
||||
132
javascript/ql/test/library-tests/Promises/flow.js
Normal file
132
javascript/ql/test/library-tests/Promises/flow.js
Normal file
@@ -0,0 +1,132 @@
|
||||
(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!
|
||||
|
||||
function createPromise(src) {
|
||||
return Promise.resolve(src);
|
||||
}
|
||||
createPromise(source).then(v => sink(v)); // NOT OK!
|
||||
|
||||
var p8 = new Promise((resolve, reject) => reject(source));
|
||||
var p9 = p8.then(() => {});
|
||||
var p10 = p9.finally(() => {});
|
||||
p10.catch((x) => sink(x)); // NOT OK!
|
||||
|
||||
var p11 = new Promise((resolve, reject) => reject(source));
|
||||
var p12 = p11.then(() => {});
|
||||
p12.catch(x => sink(x)); // NOT OK!
|
||||
|
||||
async function throws() {
|
||||
await new Promise((resolve, reject) => reject(source));
|
||||
}
|
||||
try {
|
||||
throws();
|
||||
} catch(e) {
|
||||
sink(e); // NOT OK!
|
||||
}
|
||||
|
||||
function chainedPromise() {
|
||||
return new Promise((resolve, reject) => reject(source)).then(() => {});
|
||||
}
|
||||
chainedPromise().then(() => {}).catch(e => sink(e)); // NOT OK!
|
||||
|
||||
function leaksResolvedPromise(p) {
|
||||
p.then(x => sink(x)); // NOT OK!
|
||||
}
|
||||
leaksResolvedPromise(Promise.resolve(source));
|
||||
|
||||
function leaksRejectedPromise(p) {
|
||||
p.catch(e => sink(e)); // NOT OK!
|
||||
}
|
||||
leaksRejectedPromise(new Promise((resolve, reject) => reject(source)));
|
||||
|
||||
function leaksRejectedAgain(p) {
|
||||
("foo", p).then(() => {}).catch(e => sink(e)); // NOT OK!
|
||||
}
|
||||
leaksRejectedAgain(new Promise((resolve, reject) => reject(source)).then(() => {}));
|
||||
|
||||
async function returnsRejected(p) {
|
||||
try {
|
||||
await p;
|
||||
} catch(e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
var foo = returnsRejected(new Promise((resolve, reject) => reject(source)));
|
||||
sink(foo); // NOT OK!
|
||||
|
||||
new Promise((resolve, reject) => reject("BLA")).catch(x => {return source}).then(x => sink(x)); // NOT OK
|
||||
|
||||
new Promise((resolve, reject) => reject("BLA")).finally(x => {throw source}).catch(x => sink(x)); // NOT OK
|
||||
|
||||
var rejected = new Promise((resolve, reject) => reject(source));
|
||||
|
||||
new Promise((resolve, reject) => reject("BLA")).finally(x => rejected).catch(x => sink(x)); // NOT OK
|
||||
|
||||
new Promise((resolve, reject) => reject("BLA")).catch(x => rejected).then(x => sink(x)) // OK
|
||||
|
||||
new Promise((resolve, reject) => reject("BLA")).catch(x => rejected).catch(x => sink(x)) // NOT OK
|
||||
|
||||
var resolved = Promise.resolve(source);
|
||||
|
||||
new Promise((resolve, reject) => reject("BLA")).catch(x => resolved).catch(x => sink(x)) // OK
|
||||
|
||||
new Promise((resolve, reject) => reject("BLA")).catch(x => resolved).then(x => sink(x)) // NOT OK
|
||||
|
||||
Promise.resolve(123).then(x => resolved).catch(x => sink(x)) // OK
|
||||
|
||||
Promise.resolve(123).then(x => resolved).then(x => sink(x)) // NOT OK
|
||||
|
||||
Promise.resolve(123).then(x => rejected).catch(x => sink(x)) // NOT OK
|
||||
|
||||
Promise.resolve(123).then(x => rejected).then(x => sink(x)) // OK
|
||||
|
||||
new Promise((resolve, reject) => resolve(resolved)).then(x => sink(x)); // NOT OK
|
||||
|
||||
Promise.resolve(resolved).then(x => sink(x)); // NOT OK
|
||||
})();
|
||||
34
javascript/ql/test/library-tests/Promises/flow.qll
Normal file
34
javascript/ql/test/library-tests/Promises/flow.qll
Normal file
@@ -0,0 +1,34 @@
|
||||
import javascript
|
||||
|
||||
class Configuration extends DataFlow::Configuration {
|
||||
Configuration() { this = "PromiseDataFlowFlowTestingConfig" }
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
class TaintConfig extends TaintTracking::Configuration {
|
||||
TaintConfig() { this = "PromiseTaintFlowTestingConfig" }
|
||||
|
||||
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 c).hasFlow(source, sink)
|
||||
}
|
||||
|
||||
query predicate exclusiveTaintFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
not any(Configuration c).hasFlow(source, sink) and
|
||||
any(TaintConfig c).hasFlow(source, sink)
|
||||
}
|
||||
20
javascript/ql/test/library-tests/Promises/interflow.js
Normal file
20
javascript/ql/test/library-tests/Promises/interflow.js
Normal file
@@ -0,0 +1,20 @@
|
||||
(function () {
|
||||
function getSource() {
|
||||
var source = "source"; // step 1
|
||||
return source; // step 2
|
||||
}
|
||||
loadScript(getSource()) // step 3
|
||||
.then(function () { })
|
||||
.then(function () { })
|
||||
.catch(handleError);
|
||||
function loadScript(src) { // step 4 (is summarized)
|
||||
return new Promise(function (resolve, reject) {
|
||||
setTimeout(function (error) {
|
||||
reject(new Error('Blah: ' + src)); // step 5
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
function handleError(error) { // step 6
|
||||
sink(error); // step 7
|
||||
}
|
||||
})();
|
||||
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,38 +1,222 @@
|
||||
test_ResolvedPromiseDefinition
|
||||
| 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 |
|
||||
| flow.js:51:10:51:29 | Promise.resolve(src) | flow.js:51:26:51:28 | src |
|
||||
| flow.js:81:23:81:45 | Promise ... source) | flow.js:81:39:81:44 | source |
|
||||
| flow.js:115:17:115:39 | Promise ... source) | flow.js:115:33:115:38 | source |
|
||||
| flow.js:121:2:121:21 | Promise.resolve(123) | flow.js:121:18:121:20 | 123 |
|
||||
| flow.js:123:2:123:21 | Promise.resolve(123) | flow.js:123:18:123:20 | 123 |
|
||||
| flow.js:125:2:125:21 | Promise.resolve(123) | flow.js:125:18:125:20 | 123 |
|
||||
| flow.js:127:2:127:21 | Promise.resolve(123) | flow.js:127:18:127:20 | 123 |
|
||||
| flow.js:131:2:131:26 | Promise ... solved) | flow.js:131:18:131:25 | resolved |
|
||||
| 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
|
||||
| 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:67:42:75 | () => { } |
|
||||
| flow.js:48:2:48:36 | new Pro ... urce }) | flow.js:48:44:48:55 | x => sink(x) |
|
||||
| flow.js:103:2:103:48 | new Pro ... "BLA")) | flow.js:103:56:103:75 | x => {return source} |
|
||||
| flow.js:105:2:105:48 | new Pro ... "BLA")) | flow.js:105:58:105:76 | x => {throw source} |
|
||||
| flow.js:109:2:109:48 | new Pro ... "BLA")) | flow.js:109:58:109:70 | x => rejected |
|
||||
| flow.js:111:2:111:48 | new Pro ... "BLA")) | flow.js:111:56:111:68 | x => rejected |
|
||||
| flow.js:113:2:113:48 | new Pro ... "BLA")) | flow.js:113:56:113:68 | x => rejected |
|
||||
| flow.js:117:2:117:48 | new Pro ... "BLA")) | flow.js:117:56:117:68 | x => resolved |
|
||||
| flow.js:119:2:119:48 | new Pro ... "BLA")) | flow.js:119:56:119:68 | x => resolved |
|
||||
| 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
|
||||
| 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:36 | new Pro ... urce }) | flow.js:48:14:48:35 | () => { ... ource } |
|
||||
| flow.js:55:11:55:58 | new Pro ... ource)) | flow.js:55:23:55:57 | (resolv ... source) |
|
||||
| flow.js:60:12:60:59 | new Pro ... ource)) | flow.js:60:24:60:58 | (resolv ... source) |
|
||||
| flow.js:65:9:65:56 | new Pro ... ource)) | flow.js:65:21:65:55 | (resolv ... source) |
|
||||
| flow.js:74:10:74:57 | new Pro ... ource)) | flow.js:74:22:74:56 | (resolv ... source) |
|
||||
| flow.js:86:23:86:70 | new Pro ... ource)) | flow.js:86:35:86:69 | (resolv ... source) |
|
||||
| flow.js:91:21:91:68 | new Pro ... ource)) | flow.js:91:33:91:67 | (resolv ... source) |
|
||||
| flow.js:100:28:100:75 | new Pro ... ource)) | flow.js:100:40:100:74 | (resolv ... source) |
|
||||
| flow.js:103:2:103:48 | new Pro ... "BLA")) | flow.js:103:14:103:47 | (resolv ... ("BLA") |
|
||||
| flow.js:105:2:105:48 | new Pro ... "BLA")) | flow.js:105:14:105:47 | (resolv ... ("BLA") |
|
||||
| flow.js:107:17:107:64 | new Pro ... ource)) | flow.js:107:29:107:63 | (resolv ... source) |
|
||||
| flow.js:109:2:109:48 | new Pro ... "BLA")) | flow.js:109:14:109:47 | (resolv ... ("BLA") |
|
||||
| flow.js:111:2:111:48 | new Pro ... "BLA")) | flow.js:111:14:111:47 | (resolv ... ("BLA") |
|
||||
| flow.js:113:2:113:48 | new Pro ... "BLA")) | flow.js:113:14:113:47 | (resolv ... ("BLA") |
|
||||
| flow.js:117:2:117:48 | new Pro ... "BLA")) | flow.js:117:14:117:47 | (resolv ... ("BLA") |
|
||||
| flow.js:119:2:119:48 | new Pro ... "BLA")) | flow.js:119:14:119:47 | (resolv ... ("BLA") |
|
||||
| flow.js:129:2:129:52 | new Pro ... olved)) | flow.js:129:14:129:51 | (resolv ... solved) |
|
||||
| interflow.js:11:12:15:6 | new Pro ... \\n }) | interflow.js:11:24:15:5 | functio ... ;\\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 } |
|
||||
| promises.js:43:19:45:6 | Q.Promi ... \\n }) | promises.js:43:29:45:5 | functio ... ;\\n } |
|
||||
test_PromiseDefinition_getAFinallyHandler
|
||||
| flow.js:105:2:105:48 | new Pro ... "BLA")) | flow.js:105:58:105:76 | x => {throw source} |
|
||||
| flow.js:109:2:109:48 | new Pro ... "BLA")) | flow.js:109:58:109:70 | x => rejected |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:26:20:28:3 | (v) => ... v;\\n } |
|
||||
test_PromiseDefinition
|
||||
| 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:36 | new Pro ... urce }) |
|
||||
| flow.js:55:11:55:58 | new Pro ... ource)) |
|
||||
| flow.js:60:12:60:59 | new Pro ... ource)) |
|
||||
| flow.js:65:9:65:56 | new Pro ... ource)) |
|
||||
| flow.js:74:10:74:57 | new Pro ... ource)) |
|
||||
| flow.js:86:23:86:70 | new Pro ... ource)) |
|
||||
| flow.js:91:21:91:68 | new Pro ... ource)) |
|
||||
| flow.js:100:28:100:75 | new Pro ... ource)) |
|
||||
| flow.js:103:2:103:48 | new Pro ... "BLA")) |
|
||||
| flow.js:105:2:105:48 | new Pro ... "BLA")) |
|
||||
| flow.js:107:17:107:64 | new Pro ... ource)) |
|
||||
| flow.js:109:2:109:48 | new Pro ... "BLA")) |
|
||||
| flow.js:111:2:111:48 | new Pro ... "BLA")) |
|
||||
| flow.js:113:2:113:48 | new Pro ... "BLA")) |
|
||||
| flow.js:117:2:117:48 | new Pro ... "BLA")) |
|
||||
| flow.js:119:2:119:48 | new Pro ... "BLA")) |
|
||||
| flow.js:129:2:129:52 | new Pro ... olved)) |
|
||||
| interflow.js:11:12:15:6 | 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
|
||||
| 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:64 | () => { } |
|
||||
| flow.js:42:2:42:49 | new Pro ... ource)) | flow.js:42:56:42:64 | () => { } |
|
||||
| flow.js:55:11:55:58 | new Pro ... ource)) | flow.js:56:19:56:26 | () => {} |
|
||||
| flow.js:60:12:60:59 | new Pro ... ource)) | flow.js:61:21:61:28 | () => {} |
|
||||
| flow.js:74:10:74:57 | new Pro ... ource)) | flow.js:74:64:74:71 | () => {} |
|
||||
| flow.js:91:21:91:68 | new Pro ... ource)) | flow.js:91:75:91:82 | () => {} |
|
||||
| flow.js:105:2:105:48 | new Pro ... "BLA")) | flow.js:105:58:105:76 | x => {throw source} |
|
||||
| flow.js:109:2:109:48 | new Pro ... "BLA")) | flow.js:109:58:109:70 | x => rejected |
|
||||
| flow.js:129:2:129:52 | new Pro ... olved)) | flow.js:129:59:129:70 | x => sink(x) |
|
||||
| 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
|
||||
| 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 |
|
||||
| flow.js:55:11:55:58 | new Pro ... ource)) | flow.js:55:33:55:38 | reject |
|
||||
| flow.js:60:12:60:59 | new Pro ... ource)) | flow.js:60:34:60:39 | reject |
|
||||
| flow.js:65:9:65:56 | new Pro ... ource)) | flow.js:65:31:65:36 | reject |
|
||||
| flow.js:74:10:74:57 | new Pro ... ource)) | flow.js:74:32:74:37 | reject |
|
||||
| flow.js:86:23:86:70 | new Pro ... ource)) | flow.js:86:45:86:50 | reject |
|
||||
| flow.js:91:21:91:68 | new Pro ... ource)) | flow.js:91:43:91:48 | reject |
|
||||
| flow.js:100:28:100:75 | new Pro ... ource)) | flow.js:100:50:100:55 | reject |
|
||||
| flow.js:103:2:103:48 | new Pro ... "BLA")) | flow.js:103:24:103:29 | reject |
|
||||
| flow.js:105:2:105:48 | new Pro ... "BLA")) | flow.js:105:24:105:29 | reject |
|
||||
| flow.js:107:17:107:64 | new Pro ... ource)) | flow.js:107:39:107:44 | reject |
|
||||
| flow.js:109:2:109:48 | new Pro ... "BLA")) | flow.js:109:24:109:29 | reject |
|
||||
| flow.js:111:2:111:48 | new Pro ... "BLA")) | flow.js:111:24:111:29 | reject |
|
||||
| flow.js:113:2:113:48 | new Pro ... "BLA")) | flow.js:113:24:113:29 | reject |
|
||||
| flow.js:117:2:117:48 | new Pro ... "BLA")) | flow.js:117:24:117:29 | reject |
|
||||
| flow.js:119:2:119:48 | new Pro ... "BLA")) | flow.js:119:24:119:29 | reject |
|
||||
| flow.js:129:2:129:52 | new Pro ... olved)) | flow.js:129:24:129:29 | reject |
|
||||
| interflow.js:11:12:15:6 | new Pro ... \\n }) | interflow.js:11:43:11:48 | 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
|
||||
| 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 |
|
||||
| flow.js:55:11:55:58 | new Pro ... ource)) | flow.js:55:24:55:30 | resolve |
|
||||
| flow.js:60:12:60:59 | new Pro ... ource)) | flow.js:60:25:60:31 | resolve |
|
||||
| flow.js:65:9:65:56 | new Pro ... ource)) | flow.js:65:22:65:28 | resolve |
|
||||
| flow.js:74:10:74:57 | new Pro ... ource)) | flow.js:74:23:74:29 | resolve |
|
||||
| flow.js:86:23:86:70 | new Pro ... ource)) | flow.js:86:36:86:42 | resolve |
|
||||
| flow.js:91:21:91:68 | new Pro ... ource)) | flow.js:91:34:91:40 | resolve |
|
||||
| flow.js:100:28:100:75 | new Pro ... ource)) | flow.js:100:41:100:47 | resolve |
|
||||
| flow.js:103:2:103:48 | new Pro ... "BLA")) | flow.js:103:15:103:21 | resolve |
|
||||
| flow.js:105:2:105:48 | new Pro ... "BLA")) | flow.js:105:15:105:21 | resolve |
|
||||
| flow.js:107:17:107:64 | new Pro ... ource)) | flow.js:107:30:107:36 | resolve |
|
||||
| flow.js:109:2:109:48 | new Pro ... "BLA")) | flow.js:109:15:109:21 | resolve |
|
||||
| flow.js:111:2:111:48 | new Pro ... "BLA")) | flow.js:111:15:111:21 | resolve |
|
||||
| flow.js:113:2:113:48 | new Pro ... "BLA")) | flow.js:113:15:113:21 | resolve |
|
||||
| flow.js:117:2:117:48 | new Pro ... "BLA")) | flow.js:117:15:117:21 | resolve |
|
||||
| flow.js:119:2:119:48 | new Pro ... "BLA")) | flow.js:119:15:119:21 | resolve |
|
||||
| flow.js:129:2:129:52 | new Pro ... olved)) | flow.js:129:15:129:21 | resolve |
|
||||
| interflow.js:11:12:15:6 | new Pro ... \\n }) | interflow.js:11:34:11:40 | 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
|
||||
| flow.js:32:2:32:49 | new Pro ... ource)) | flow.js:32:57:32:68 | x => sink(x) |
|
||||
| flow.js:48:2:48:36 | new Pro ... urce }) | flow.js:48:44:48:55 | x => sink(x) |
|
||||
| flow.js:103:2:103:48 | new Pro ... "BLA")) | flow.js:103:56:103:75 | x => {return source} |
|
||||
| flow.js:111:2:111:48 | new Pro ... "BLA")) | flow.js:111:56:111:68 | x => rejected |
|
||||
| flow.js:113:2:113:48 | new Pro ... "BLA")) | flow.js:113:56:113:68 | x => rejected |
|
||||
| flow.js:117:2:117:48 | new Pro ... "BLA")) | flow.js:117:56:117:68 | x => resolved |
|
||||
| flow.js:119:2:119:48 | new Pro ... "BLA")) | flow.js:119:56:119:68 | x => resolved |
|
||||
| promises.js:10:18:17:4 | new Pro ... );\\n }) | promises.js:23:18:25:3 | (v) => ... v;\\n } |
|
||||
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:58:34:58 | 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:83:40:83 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:44:92:44:92 | a |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:46:60:46:60 | a |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:48:54:48:54 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:53:39:53:39 | v |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:58:24:58:24 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:62:22:62:22 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:70:8:70:8 | e |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:76:50:76:50 | e |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:79:20:79:20 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:84:21:84:21 | e |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:89:45:89:45 | e |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:101:7:101:9 | foo |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:103:93:103:93 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:105:95:105:95 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:109:89:109:89 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:113:87:113:87 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:119:86:119:86 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:123:58:123:58 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:125:59:125:59 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:129:69:129:69 | x |
|
||||
| flow.js:2:15:2:22 | "source" | flow.js:131:43:131:43 | x |
|
||||
exclusiveTaintFlow
|
||||
| interflow.js:3:18:3:25 | "source" | interflow.js:18:10:18:14 | error |
|
||||
|
||||
@@ -7,3 +7,4 @@ import PromiseDefinition_getAResolveHandler
|
||||
import PromiseDefinition_getRejectParameter
|
||||
import PromiseDefinition_getResolveParameter
|
||||
import PromiseDefinition_getACatchHandler
|
||||
import flow
|
||||
Reference in New Issue
Block a user