JS: Add 'Awaited' token

This commit is contained in:
Asger F
2023-10-04 20:00:09 +02:00
parent 32070abb27
commit 293899d648
3 changed files with 71 additions and 0 deletions

View File

@@ -50,6 +50,9 @@ private module Cached {
TConstructorThisArgumentNode(InvokeExpr e) { e instanceof NewExpr or e instanceof SuperCall } or
TConstructorThisPostUpdate(Constructor ctor) or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
TFlowSummaryIntermediateAwaitStoreNode(FlowSummaryImpl::Private::SummaryNode sn) {
FlowSummaryImpl::Private::Steps::summaryStoreStep(sn, MkAwaited(), _)
} or
}
import Cached

View File

@@ -23,6 +23,23 @@ class FlowSummaryNode extends DataFlow::Node, TFlowSummaryNode {
override string toString() { result = this.getSummaryNode().toString() }
}
class FlowSummaryIntermediateAwaitStoreNode extends DataFlow::Node,
TFlowSummaryIntermediateAwaitStoreNode
{
FlowSummaryImpl::Private::SummaryNode getSummaryNode() {
this = TFlowSummaryIntermediateAwaitStoreNode(result)
}
/** Gets the summarized callable that this node belongs to. */
FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() {
result = this.getSummaryNode().getSummarizedCallable()
}
override string toString() {
result = this.getSummaryNode().toString() + " [intermediate node for Awaited store]"
}
}
cached
newtype TReturnKind =
MkNormalReturnKind() or
@@ -236,6 +253,8 @@ predicate nodeIsHidden(Node node) {
DataFlow::PathNode::shouldNodeBeHidden(node)
or
node instanceof FlowSummaryNode
or
node instanceof FlowSummaryIntermediateAwaitStoreNode
}
predicate neverSkipInPathGraph(Node node) {
@@ -552,6 +571,21 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
valuePreservingStep(node1, node2) and
nodeGetEnclosingCallable(pragma[only_bind_out](node1)) =
nodeGetEnclosingCallable(pragma[only_bind_out](node2))
or
exists(FlowSummaryImpl::Private::SummaryNode input, FlowSummaryImpl::Private::SummaryNode output |
FlowSummaryImpl::Private::Steps::summaryStoreStep(input, MkAwaited(), output) and
node1 = TFlowSummaryNode(input) and
(
node2 = TFlowSummaryNode(output) and
not node2 instanceof PostUpdateNode // When doing a store-back, do not add the local flow edge
or
node2 = TFlowSummaryIntermediateAwaitStoreNode(input)
)
or
FlowSummaryImpl::Private::Steps::summaryReadStep(input, MkAwaited(), output) and
node1 = TFlowSummaryNode(input) and
node2 = TFlowSummaryNode(output)
)
}
predicate localMustFlowStep(Node node1, Node node2) { node1 = node2.getImmediatePredecessor() }
@@ -589,7 +623,11 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(),
contentSet, node2.(FlowSummaryNode).getSummaryNode())
|
not isSpecialContentSet(contentSet) and
c = contentSet
or
contentSet = MkAwaited() and
c = ContentSet::promiseValue()
)
}
@@ -620,6 +658,14 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
or
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
node2.(FlowSummaryNode).getSummaryNode()) and
not isSpecialContentSet(c)
or
// Store into Awaited
exists(FlowSummaryImpl::Private::SummaryNode input, FlowSummaryImpl::Private::SummaryNode output |
FlowSummaryImpl::Private::Steps::summaryStoreStep(input, MkAwaited(), output) and
node1 = TFlowSummaryIntermediateAwaitStoreNode(input) and
node2 = TFlowSummaryNode(output) and
c = ContentSet::promiseValue()
)
}
@@ -630,6 +676,15 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
*/
predicate clearsContent(Node n, ContentSet c) {
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
or
// Clear promise content before storing into promise value, to avoid creating nested promises
n = TFlowSummaryIntermediateAwaitStoreNode(_) and
c = MkPromiseFilter()
or
// After reading from Awaited, the output must not be stored in a promise content
FlowSummaryImpl::Private::Steps::summaryReadStep(_, MkAwaited(),
n.(FlowSummaryNode).getSummaryNode()) and
c = MkPromiseFilter()
}
/**
@@ -638,6 +693,12 @@ predicate clearsContent(Node n, ContentSet c) {
*/
predicate expectsContent(Node n, ContentSet c) {
FlowSummaryImpl::Private::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
or
// After storing into Awaited, the result must be stored in a promise-content.
// There is a value step from the input directly to this node, hence the need for expectsContent.
FlowSummaryImpl::Private::Steps::summaryStoreStep(_, MkAwaited(),
n.(FlowSummaryNode).getSummaryNode()) and
c = MkPromiseFilter()
}
/**

View File

@@ -200,6 +200,11 @@ SummaryComponent interpretComponentSpecific(Private::AccessPathToken c) {
c.getName() = "ReturnValue" and
c.getAnArgument() = "exception" and
result = SummaryComponent::return(MkExceptionalReturnKind())
or
// Awaited is mapped down to a combination steps that handle coercion and promise-flattening.
c.getName() = "Awaited" and
c.getNumArgument() = 0 and
result = SummaryComponent::content(MkAwaited())
}
private string getMadStringFromContentSetAux(ContentSet cs) {
@@ -236,6 +241,8 @@ private string getMadStringFromContentSetAux(ContentSet cs) {
cs = getPromiseContent(awaitedArg) and
result = "Awaited[" + awaitedArg + "]"
)
or
cs = MkAwaited() and result = "Awaited"
}
private string getMadStringFromContentSet(ContentSet cs) {