Merge pull request #19007 from asgerf/js/api-graph-awaited-return

JS: Fix bug in API graphs getPromised() missing async function returns
This commit is contained in:
Asger F
2025-03-14 10:36:16 +01:00
committed by GitHub
2 changed files with 38 additions and 24 deletions

View File

@@ -4,6 +4,7 @@
import javascript
private import dataflow.internal.StepSummary
private import semmle.javascript.dataflow.internal.FlowSteps
/**
* A call to the `Promise` constructor, such as `new Promise((resolve, reject) => { ... })`.
@@ -397,6 +398,17 @@ module PromiseFlow {
value = call.getCallback(0).getExceptionalReturn() and
obj = call
)
or
exists(DataFlow::FunctionNode f | f.getFunction().isAsync() |
// ordinary return
prop = valueProp() and
value = f.getAReturn() and
obj = f.getReturnNode()
or
// exceptional return
prop = errorProp() and
localExceptionStepWithAsyncFlag(value, obj, true)
)
}
/**
@@ -525,30 +537,6 @@ private class PromiseTaintStep extends TaintTracking::LegacyTaintStep {
* Defines flow steps for return on async functions.
*/
private module AsyncReturnSteps {
private predicate valueProp = Promises::valueProp/0;
private predicate errorProp = Promises::errorProp/0;
private import semmle.javascript.dataflow.internal.FlowSteps
/**
* A data-flow step for ordinary and exceptional returns from async functions.
*/
private class AsyncReturn extends LegacyPreCallGraphStep {
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
exists(DataFlow::FunctionNode f | f.getFunction().isAsync() |
// ordinary return
prop = valueProp() and
pred = f.getAReturn() and
succ = f.getReturnNode()
or
// exceptional return
prop = errorProp() and
localExceptionStepWithAsyncFlag(pred, succ, true)
)
}
}
/**
* A data-flow step for ordinary return from an async function in a taint configuration.
*/

View File

@@ -0,0 +1,26 @@
import * as t from "testlib";
async function getData1() {
const data = await fetch("https://example.com/content");
return data.json(); /* def=moduleImport("testlib").getMember("exports").getMember("foo").getParameter(0).getReturn().getPromised() */
}
export function use1() {
t.foo(() => getData1());
}
async function getData2() {
const data = await fetch("https://example.com/content");
return data.json(); /* def=moduleImport("testlib").getMember("exports").getMember("foo").getParameter(0).getReturn().getPromised() */
}
export function use2() {
t.foo(getData2);
}
export function use3() {
t.foo(async () => {
const data = await fetch("https://example.com/content");
return data.json(); /* def=moduleImport("testlib").getMember("exports").getMember("foo").getParameter(0).getReturn().getPromised() */
});
}