Skip to content

JS: add DataFlow::getEnclosingExpr to get Expr for potentially reflective calls #2270

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 3 commits into from
Nov 13, 2019
Merged
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions javascript/ql/src/Statements/UseOfReturnlessFunction.ql
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ where
msg = "the $@ does not return anything, yet the return value from the call to " + call.getCalleeName() + " is used." and
name = "callback function"
) and
not benignContext(call.asExpr()) and
not benignContext(call.getEnclosingExpr()) and
not lastStatementHasNoEffect(func) and
// anonymous one-shot closure. Those are used in weird ways and we ignore them.
not oneshotClosure(call.asExpr())
not oneshotClosure(call.getEnclosingExpr())
select
call, msg, func, name
22 changes: 22 additions & 0 deletions javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ module DataFlow {
/** Gets the expression corresponding to this data flow node, if any. */
Expr asExpr() { this = TValueNode(result) }

/**
* Gets the expression enclosing this data flow node.
* In most cases the result is the same as `asExpr()`, however this method
* additionally the `InvokeExpr` corresponding to reflective calls, and the `Parameter`
* for a `DataFlow::ParameterNode`.
*/
Expr getEnclosingExpr() {
result = asExpr() or
this = DataFlow::reflectiveCallNode(result) or
result = this.(ParameterNode).getParameter()
}

/** Gets the AST node corresponding to this data flow node, if any. */
ASTNode getAstNode() { none() }

Expand Down Expand Up @@ -950,6 +962,16 @@ module DataFlow {
* Gets a pseudo-node representing the root of a global access path.
*/
DataFlow::Node globalAccessPathRootPseudoNode() { result instanceof TGlobalAccessPathRoot }

/**
* Gets a data flow node representing the underlying call performed by the given
* call to `Function.prototype.call` or `Function.prototype.apply`.
*
* For example, for an expression `fn.call(x, y)`, this gets a call node with `fn` as the
* callee, `x` as the receiver, and `y` as the first argument.
*/
DataFlow::InvokeNode reflectiveCallNode(InvokeExpr expr) { result = TReflectiveCallNode(expr, _) }


/**
* Provides classes representing various kinds of calls.
Expand Down
Loading