diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index e2c5f325b0d5..08df334973f6 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -537,7 +537,6 @@ private predicate isRelevant(DataFlow::Node nd, DataFlow::Configuration cfg) { * either `pred` is an argument of `f` and `succ` the corresponding parameter, or * `pred` is a variable definition whose value is captured by `f` at `succ`. */ -pragma[noopt] private predicate callInputStep(Function f, DataFlow::Node invk, DataFlow::Node pred, DataFlow::Node succ, DataFlow::Configuration cfg) { @@ -567,6 +566,7 @@ private predicate callInputStep(Function f, DataFlow::Node invk, * Note that the summary does not take the initial step from argument to parameter * into account. */ +pragma[nomagic] private predicate reachableFromInput(Function f, DataFlow::Node invk, DataFlow::Node input, DataFlow::Node nd, DataFlow::Configuration cfg, PathSummary summary) { @@ -600,20 +600,28 @@ private predicate flowThroughCall(DataFlow::Node input, DataFlow::Node invk, * Holds if `pred` may flow into property `prop` of `succ` under configuration `cfg` * along a path summarized by `summary`. */ -private predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop, +pragma[nomagic] +private predicate storeStep(DataFlow::Node pred, DataFlow::Node succ, string prop, DataFlow::Configuration cfg, PathSummary summary) { basicStoreStep(pred, succ, prop) and summary = PathSummary::level() or - exists (Function f, DataFlow::Node mid, DataFlow::SourceNode base | + exists (Function f, DataFlow::Node mid, DataFlow::Node base | // `f` stores its parameter `pred` in property `prop` of a value that it returns, // and `succ` is an invocation of `f` reachableFromInput(f, succ, pred, mid, cfg, summary) and - base.hasPropertyWrite(prop, mid) and - base.flowsToExpr(f.getAReturnedExpr()) + returnedPropWrite(f, base, prop, mid) ) } +/** + * Holds if `f` may return `base`, which has a write of property `prop` with right-hand side `rhs`. + */ +predicate returnedPropWrite(Function f, DataFlow::SourceNode base, string prop, DataFlow::Node rhs) { + base.hasPropertyWrite(prop, rhs) and + base.flowsToExpr(f.getAReturnedExpr()) +} + /** * Holds if `rhs` is the right-hand side of a write to property `prop`, and `nd` is reachable * from the base of that write under configuration `cfg` (possibly through callees) along a