Skip to content
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

JS: Fix jump steps generated by IIFEs and exception flow #18043

Open
wants to merge 19 commits into
base: js/shared-dataflow-branch
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -1217,14 +1217,29 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {

predicate localMustFlowStep(Node node1, Node node2) { node1 = node2.getImmediatePredecessor() }

/**
* Holds if `node1 -> node2` should be removed as a jump step.
*
* Currently this is done as a workaround for the local steps generated from IIFEs.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Currently"?
Is that hinting towards plans for a another solution in the future?

Copy link
Contributor Author

@asgerf asgerf Nov 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general this predicate can populated with jump steps that should be excluded, and currently the only use-case for this is the workaround mentioned. So it was meant to imply that other things could get added to the predicate as well.

*/
private predicate excludedJumpStep(Node node1, Node node2) {
exists(ImmediatelyInvokedFunctionExpr iife |
iife.argumentPassing(node2.asExpr(), node1.asExpr())
or
node1 = iife.getAReturnedExpr().flow() and
node2 = iife.getInvocation().flow()
)
}

/**
* Holds if data can flow from `node1` to `node2` through a non-local step
* that does not follow a call edge. For example, a step through a global
* variable.
*/
predicate jumpStep(Node node1, Node node2) {
valuePreservingStep(node1, node2) and
node1.getContainer() != node2.getContainer()
node1.getContainer() != node2.getContainer() and
not excludedJumpStep(node1, node2)
or
FlowSummaryPrivate::Steps::summaryJumpStep(node1.(FlowSummaryNode).getSummaryNode(),
node2.(FlowSummaryNode).getSummaryNode())
Expand Down
12 changes: 6 additions & 6 deletions javascript/ql/test/library-tests/TripleDot/iife.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ function f1() {
return p; // argument to return
})(x);
}
sink(inner(source("f1.1"))); // $ hasValueFlow=f1.1 SPURIOUS: hasValueFlow=f1.2
sink(inner(source("f1.2"))); // $ hasValueFlow=f1.2 SPURIOUS: hasValueFlow=f1.1
sink(inner(source("f1.1"))); // $ hasValueFlow=f1.1
sink(inner(source("f1.2"))); // $ hasValueFlow=f1.2
}

function f2() {
Expand All @@ -16,8 +16,8 @@ function f2() {
})(x);
return y;
}
sink(inner(source("f2.1"))); // $ hasValueFlow=f2.1 SPURIOUS: hasValueFlow=f2.2
sink(inner(source("f2.2"))); // $ hasValueFlow=f2.2 SPURIOUS: hasValueFlow=f2.1
sink(inner(source("f2.1"))); // $ MISSING: hasValueFlow=f2.1
sink(inner(source("f2.2"))); // $ MISSING: hasValueFlow=f2.2
}

function f3() {
Expand All @@ -26,8 +26,8 @@ function f3() {
return x; // captured variable to return
})();
}
sink(inner(source("f3.1"))); // $ hasValueFlow=f3.1 SPURIOUS: hasValueFlow=f3.2
sink(inner(source("f3.2"))); // $ hasValueFlow=f3.2 SPURIOUS: hasValueFlow=f3.1
sink(inner(source("f3.1"))); // $ hasValueFlow=f3.1
sink(inner(source("f3.2"))); // $ hasValueFlow=f3.2
}

function f4() {
Expand Down