mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
JavaScript: Improve caching of getACallee and related predicates.
This commit is contained in:
@@ -28,33 +28,6 @@ predicate guardsAgainstMissingNew(Function f) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `callee` is a function that may be invoked at callsite `cs`,
|
||||
* where `imprecision` is a heuristic measure of how likely it is that `callee`
|
||||
* is only suggested as a potential callee due to imprecise analysis of global
|
||||
* variables and is not, in fact, a viable callee at all.
|
||||
*/
|
||||
predicate calls(DataFlow::InvokeNode cs, Function callee, int imprecision) {
|
||||
callee = cs.getACallee() and
|
||||
(
|
||||
// if global flow was used to derive the callee, we may be imprecise
|
||||
if cs.isIndefinite("global")
|
||||
then
|
||||
// callees within the same file are probably genuine
|
||||
callee.getFile() = cs.getFile() and imprecision = 0
|
||||
or
|
||||
// calls to global functions declared in an externs file are fairly
|
||||
// safe as well
|
||||
callee.inExternsFile() and imprecision = 1
|
||||
or
|
||||
// otherwise we make worst-case assumptions
|
||||
imprecision = 2
|
||||
else
|
||||
// no global flow, so no imprecision
|
||||
imprecision = 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function that may be invoked at `cs`, preferring callees that
|
||||
* are less likely to be derived due to analysis imprecision and excluding
|
||||
@@ -62,7 +35,13 @@ predicate calls(DataFlow::InvokeNode cs, Function callee, int imprecision) {
|
||||
* `true` if `cs` is a `new` expression, and to `false` otherwise.
|
||||
*/
|
||||
Function getALikelyCallee(DataFlow::InvokeNode cs, boolean isNew) {
|
||||
calls(cs, result, min(int p | calls(cs, _, p))) and
|
||||
result = min(Function callee, int imprecision |
|
||||
callee = cs.getACallee(imprecision)
|
||||
|
|
||||
callee
|
||||
order by
|
||||
imprecision
|
||||
) and
|
||||
not cs.isUncertain() and
|
||||
not whitelistedCall(cs) and
|
||||
not whitelistedCallee(result) and
|
||||
|
||||
@@ -81,21 +81,20 @@ class InvokeNode extends DataFlow::DefaultSourceNode {
|
||||
}
|
||||
|
||||
/** Gets an abstract value representing possible callees of this call site. */
|
||||
cached
|
||||
AbstractValue getACalleeValue() { result = impl.getCalleeNode().analyze().getAValue() }
|
||||
|
||||
/** Gets a potential callee based on dataflow analysis results. */
|
||||
private Function getACalleeFromDataflow() {
|
||||
result = getACalleeValue().(AbstractCallable).getFunction()
|
||||
}
|
||||
AbstractValue getACalleeValue() { result = InvokeNode::getACalleeValue(this) }
|
||||
|
||||
/** Gets a potential callee of this call site. */
|
||||
Function getACallee() {
|
||||
result = getACalleeFromDataflow()
|
||||
or
|
||||
not exists(getACalleeFromDataflow()) and
|
||||
result = impl.(DataFlow::Impl::ExplicitInvokeNode).asExpr().(InvokeExpr).getResolvedCallee()
|
||||
}
|
||||
Function getACallee() { result = InvokeNode::getACallee(this) }
|
||||
|
||||
/**
|
||||
* Gets a callee of this call site where `imprecision` is a heuristic measure of how
|
||||
* likely it is that `callee` is only suggested as a potential callee due to
|
||||
* imprecise analysis of global variables and is not, in fact, a viable callee at all.
|
||||
*
|
||||
* Callees with imprecision zero, in particular, have either been derived without
|
||||
* considering global variables, or are calls to a global variable within the same file.
|
||||
*/
|
||||
Function getACallee(int imprecision) { result = InvokeNode::getACallee(this, imprecision) }
|
||||
|
||||
/**
|
||||
* Holds if the approximation of possible callees for this call site is
|
||||
@@ -136,6 +135,60 @@ class InvokeNode extends DataFlow::DefaultSourceNode {
|
||||
predicate isUncertain() { isImprecise() or isIncomplete() }
|
||||
}
|
||||
|
||||
/** Auxiliary module used to cache a few related predicates together. */
|
||||
cached
|
||||
private module InvokeNode {
|
||||
/** Gets an abstract value representing possible callees of `invk`. */
|
||||
cached
|
||||
AbstractValue getACalleeValue(InvokeNode invk) {
|
||||
result = invk.getCalleeNode().analyze().getAValue()
|
||||
}
|
||||
|
||||
/** Gets a potential callee of `invk` based on dataflow analysis results. */
|
||||
private Function getACalleeFromDataflow(InvokeNode invk) {
|
||||
result = getACalleeValue(invk).(AbstractCallable).getFunction()
|
||||
}
|
||||
|
||||
/** Gets a potential callee of `invk`. */
|
||||
cached
|
||||
Function getACallee(InvokeNode invk) {
|
||||
result = getACalleeFromDataflow(invk)
|
||||
or
|
||||
not exists(getACalleeFromDataflow(invk)) and
|
||||
result = invk.(DataFlow::Impl::ExplicitInvokeNode).asExpr().(InvokeExpr).getResolvedCallee()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a callee of `invk` where `imprecision` is a heuristic measure of how
|
||||
* likely it is that `callee` is only suggested as a potential callee due to
|
||||
* imprecise analysis of global variables and is not, in fact, a viable callee at all.
|
||||
*
|
||||
* Callees with imprecision zero, in particular, have either been derived without
|
||||
* considering global variables, or are calls to a global variable within the same file.
|
||||
*/
|
||||
cached
|
||||
Function getACallee(InvokeNode invk, int imprecision) {
|
||||
result = getACallee(invk) and
|
||||
(
|
||||
// if global flow was used to derive the callee, we may be imprecise
|
||||
if invk.isIndefinite("global")
|
||||
then
|
||||
// callees within the same file are probably genuine
|
||||
result.getFile() = invk.getFile() and imprecision = 0
|
||||
or
|
||||
// calls to global functions declared in an externs file are fairly
|
||||
// safe as well
|
||||
result.inExternsFile() and imprecision = 1
|
||||
or
|
||||
// otherwise we make worst-case assumptions
|
||||
imprecision = 2
|
||||
else
|
||||
// no global flow, so no imprecision
|
||||
imprecision = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A data flow node corresponding to a function call without `new`. */
|
||||
class CallNode extends InvokeNode {
|
||||
override DataFlow::Impl::CallNodeDef impl;
|
||||
|
||||
@@ -20,12 +20,7 @@ predicate shouldTrackProperties(AbstractValue obj) {
|
||||
/**
|
||||
* Holds if `invk` may invoke `f`.
|
||||
*/
|
||||
predicate calls(DataFlow::InvokeNode invk, Function f) {
|
||||
if invk.isIndefinite("global")
|
||||
then (
|
||||
f = invk.getACallee() and f.getFile() = invk.getFile()
|
||||
) else f = invk.getACallee()
|
||||
}
|
||||
predicate calls(DataFlow::InvokeNode invk, Function f) { f = invk.getACallee(0) }
|
||||
|
||||
/**
|
||||
* Holds if `invk` may invoke `f` indirectly through the given `callback` argument.
|
||||
|
||||
Reference in New Issue
Block a user