implement precise data-flow steps for Promise.all

This commit is contained in:
Erik Krogh Kristensen 2020-05-14 18:52:53 +02:00
Родитель 5c9fb2312e
Коммит e98f794dab
2 изменённых файлов: 49 добавлений и 5 удалений

Просмотреть файл

@ -251,13 +251,17 @@ private module ArrayDataFlow {
/**
* A step for creating an array and storing the elements in the array.
*/
private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::Node {
ArrayCreationStep() { this instanceof DataFlow::ArrayCreationNode }
private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::ArrayCreationNode {
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
prop = arrayElement() and
element = this.(DataFlow::ArrayCreationNode).getAnElement() and
element = this.getAnElement() and
obj = this
or
exists(int i |
element = this.getElement(i) and
obj = this and
prop = i.toString()
)
}
}

Просмотреть файл

@ -85,7 +85,7 @@ private class ES2015PromiseDefinition extends PromiseDefinition, DataFlow::NewNo
*/
abstract class PromiseCreationCall extends DataFlow::CallNode {
/**
* Gets the value this promise is resolved with.
* Gets a value this promise is resolved with.
*/
abstract DataFlow::Node getValue();
}
@ -95,6 +95,16 @@ abstract class PromiseCreationCall extends DataFlow::CallNode {
*/
abstract class ResolvedPromiseDefinition extends PromiseCreationCall { }
/**
* A promise that is created using a `Promise.all(array)` call.
*/
abstract class PromiseAllCreation extends PromiseCreationCall {
/**
* Gets a node for the array of values given to the `Promise.all(array)` call.
*/
abstract DataFlow::Node getArrayNode();
}
/**
* A resolved promise created by the standard ECMAScript 2015 `Promise.resolve` function.
*/
@ -121,6 +131,15 @@ class AggregateES2015PromiseDefinition extends PromiseCreationCall {
}
}
/**
* An aggregated promise created using `Promise.all()`.
*/
class ES2015PromiseAllDefinition extends AggregateES2015PromiseDefinition, PromiseAllCreation {
ES2015PromiseAllDefinition() { this.getCalleeName() = "all" }
override DataFlow::Node getArrayNode() { result = getArgument(0) }
}
/**
* Common predicates shared between type-tracking and data-flow for promises.
*/
@ -303,16 +322,28 @@ private module PromiseFlow {
CreationStep() { this = promise }
override predicate store(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
not promise instanceof PromiseAllCreation and
prop = valueProp() and
pred = promise.getValue() and
succ = this
or
promise instanceof PromiseAllCreation and
prop = valueProp() and
pred = promise.(PromiseAllCreation).getArrayNode() and
succ = this
}
override predicate loadStore(DataFlow::Node pred, DataFlow::Node succ, string prop) {
// Copy the value of a resolved promise to the value of this promise.
not promise instanceof PromiseAllCreation and
prop = valueProp() and
pred = promise.getValue() and
succ = this
or
promise instanceof PromiseAllCreation and
prop = valueProp() and
pred = promise.(PromiseAllCreation).getArrayNode() and
succ = this
}
}
@ -533,6 +564,15 @@ module Bluebird {
result = getArgument(0).getALocalSource().(DataFlow::ArrayCreationNode).getAnElement()
}
}
/**
* A promise created using `Promise.all`:
*/
class BluebirdPromiseAllDefinition extends AggregateBluebirdPromiseDefinition, PromiseAllCreation {
BluebirdPromiseAllDefinition() { this.getCalleeName() = "all" }
override DataFlow::Node getArrayNode() { result = getArgument(0) }
}
}
/**