Skip to content

JS: push more context into load/store steps from the exploratory flow-analysis #10986

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 1, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,7 @@ private predicate parameterPropReadStep(
invk = getAwaitOperand(succ)
) and
callInputStep(f, invk, arg, parm, cfg) and
prop = pragma[only_bind_into](getARelevantProp(cfg)) and
(
read = parm.getAPropertyRead(prop)
or
Expand All @@ -1192,7 +1193,7 @@ private predicate reachesReturn(
isRelevant(read, cfg) and
returnExpr(f, read, _) and
summary = PathSummary::level() and
callInputStep(f, _, _, _, _) // check that a relevant result can exist.
parameterPropReadStep(_, _, _, cfg, _, _, f, _) // check that a relevant result can exist.
or
exists(DataFlow::Node mid, PathSummary oldSummary, PathSummary newSummary |
flowStep(read, cfg, mid, oldSummary) and
Expand All @@ -1202,6 +1203,33 @@ private predicate reachesReturn(
)
}

// used in `getARelevantProp`, outlined for performance
pragma[noinline]
private string getARelevantStoreProp(DataFlow::Configuration cfg) {
exists(DataFlow::Node previous | isRelevant(previous, cfg) |
basicStoreStep(previous, _, result) or
isAdditionalStoreStep(previous, _, result, cfg)
)
}

// used in `getARelevantProp`, outlined for performance
pragma[noinline]
private string getARelevantLoadProp(DataFlow::Configuration cfg) {
exists(DataFlow::Node previous | isRelevant(previous, cfg) |
basicLoadStep(previous, _, result) or
isAdditionalLoadStep(previous, _, result, cfg)
)
}

/** Gets the name of a property that is both loaded and stored according to the exploratory analysis. */
pragma[noinline]
private string getARelevantProp(DataFlow::Configuration cfg) {
result = getARelevantStoreProp(cfg) and
result = getARelevantLoadProp(cfg)
or
result = getAPropertyUsedInLoadStore(cfg)
}

/**
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
*/
Expand Down Expand Up @@ -1275,6 +1303,7 @@ private predicate reachableFromStoreBase(
) {
exists(TPathSummary s1, TPathSummary s2, DataFlow::Node rhs |
storeStep(rhs, nd, startProp, cfg, s2) and
startProp = getARelevantProp(cfg) and
endProp = startProp and
base = nd and
exists(boolean hasCall, DataFlow::FlowLabel data |
Expand All @@ -1300,6 +1329,7 @@ private predicate reachableFromStoreBase(
exists(string midProp |
reachableFromStoreBase(startProp, midProp, base, mid, cfg, oldSummary, onlyRelevantInCall) and
isAdditionalLoadStoreStep(mid, nd, midProp, endProp, cfg) and
endProp = getARelevantProp(cfg) and
newSummary = PathSummary::level()
)
|
Expand Down