mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
JavaScript: Lift call graph library to data flow graph.
This commit is contained in:
@@ -50,3 +50,4 @@
|
||||
|
||||
* HTTP header names are now always normalized to lower case to reflect the fact that they are case insensitive. In particular, the result of `HeaderDefinition.getAHeaderName`, and the first parameter of `HeaderDefinition.defines`, `ExplicitHeaderDefinition.definesExplicitly` and `RouteHandler.getAResponseHeader` is now always a lower-case string.
|
||||
* The class `JsonParseCall` has been deprecated. Use `JsonParserCall` instead.
|
||||
* The handling of spread arguments in the data flow library has been changed: `DataFlow::InvokeNode.getArgument(i)` is now only defined when there is no spread argument at or before argument position `i`, and similarly `InvokeNode.getNumArgument` is only defined for invocations without spread arguments.
|
||||
|
||||
@@ -121,8 +121,7 @@ predicate noSideEffects(Expr e) {
|
||||
e.isPure()
|
||||
or
|
||||
// `new Error(...)`, `new SyntaxError(...)`, etc.
|
||||
e instanceof NewExpr and
|
||||
forex (Function f | f = e.(CallSite).getACallee() |
|
||||
forex (Function f | f = e.flow().(DataFlow::NewNode).getACallee() |
|
||||
f.(ExternalType).getASupertype*().getName() = "Error"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@ import javascript
|
||||
/**
|
||||
* Holds if call site `cs` may invoke function `callee` as specified by `how`.
|
||||
*/
|
||||
predicate calls(CallSite cs, Function callee, string how) {
|
||||
predicate calls(DataFlow::InvokeNode cs, Function callee, string how) {
|
||||
callee = cs.getACallee() and
|
||||
(
|
||||
cs instanceof CallExpr and not cs instanceof SuperCall and
|
||||
cs instanceof DataFlow::CallNode and not cs.asExpr() instanceof SuperCall and
|
||||
how = "as a function"
|
||||
or
|
||||
cs instanceof NewExpr and
|
||||
cs instanceof DataFlow::NewNode and
|
||||
how = "using 'new'"
|
||||
)
|
||||
}
|
||||
@@ -31,7 +31,7 @@ predicate calls(CallSite cs, Function callee, string how) {
|
||||
* Holds if call site `cs` may illegally invoke function `callee` as specified by `how`;
|
||||
* `calleeDesc` describes what kind of function `callee` is.
|
||||
*/
|
||||
predicate illegalInvocation(CallSite cs, Function callee, string calleeDesc, string how) {
|
||||
predicate illegalInvocation(DataFlow::InvokeNode cs, Function callee, string calleeDesc, string how) {
|
||||
calls(cs, callee, how) and
|
||||
(
|
||||
how = "as a function" and
|
||||
@@ -44,15 +44,16 @@ predicate illegalInvocation(CallSite cs, Function callee, string calleeDesc, str
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ce` has at least one call target that isn't a constructor.
|
||||
* Holds if `ce` is a call with at least one call target that isn't a constructor.
|
||||
*/
|
||||
predicate isCallToFunction(CallExpr ce) {
|
||||
exists (Function f | f = ce.(CallSite).getACallee() |
|
||||
predicate isCallToFunction(DataFlow::InvokeNode ce) {
|
||||
ce instanceof DataFlow::CallNode and
|
||||
exists (Function f | f = ce.getACallee() |
|
||||
not f instanceof Constructor
|
||||
)
|
||||
}
|
||||
|
||||
from CallSite cs, Function callee, string calleeDesc, string how
|
||||
from DataFlow::InvokeNode cs, Function callee, string calleeDesc, string how
|
||||
where illegalInvocation(cs, callee, calleeDesc, how) and
|
||||
// filter out some easy cases
|
||||
not isCallToFunction(cs) and
|
||||
|
||||
@@ -22,8 +22,8 @@ import semmle.javascript.RestrictedLocations
|
||||
* have to call itself using `new`, so that is what we look for.
|
||||
*/
|
||||
predicate guardsAgainstMissingNew(Function f) {
|
||||
exists (CallSite new |
|
||||
new.(NewExpr).getEnclosingFunction() = f and
|
||||
exists (DataFlow::NewNode new |
|
||||
new.asExpr().getEnclosingFunction() = f and
|
||||
f = new.getACallee()
|
||||
)
|
||||
}
|
||||
@@ -34,13 +34,13 @@ predicate guardsAgainstMissingNew(Function f) {
|
||||
* 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(CallSite cs, Function callee, int imprecision) {
|
||||
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.(Locatable).getFile() and imprecision = 0
|
||||
callee.getFile() = cs.getFile() and imprecision = 0
|
||||
or
|
||||
// calls to global functions declared in an externs file are fairly
|
||||
// safe as well
|
||||
@@ -58,11 +58,11 @@ predicate calls(CallSite cs, Function callee, int imprecision) {
|
||||
* Gets a function that may be invoked at `cs`, preferring callees that
|
||||
* are less likely to be derived due to analysis imprecision.
|
||||
*/
|
||||
Function getALikelyCallee(CallSite cs) {
|
||||
Function getALikelyCallee(DataFlow::InvokeNode cs) {
|
||||
calls(cs, result, min(int p | calls(cs, _, p)))
|
||||
}
|
||||
|
||||
from Function f, NewExpr new, CallExpr call
|
||||
from Function f, DataFlow::NewNode new, DataFlow::CallNode call
|
||||
where // externs are special, so don't flag them
|
||||
not f.inExternsFile() and
|
||||
// illegal constructor calls are flagged by query 'Illegal invocation',
|
||||
@@ -71,11 +71,11 @@ where // externs are special, so don't flag them
|
||||
f = getALikelyCallee(new) and
|
||||
f = getALikelyCallee(call) and
|
||||
not guardsAgainstMissingNew(f) and
|
||||
not new.(CallSite).isUncertain() and
|
||||
not call.(CallSite).isUncertain() and
|
||||
not new.isUncertain() and
|
||||
not call.isUncertain() and
|
||||
// super constructor calls behave more like `new`, so don't flag them
|
||||
not call instanceof SuperCall and
|
||||
// reflective calls provide an explicit receiver object, so don't flag them either
|
||||
not call instanceof ReflectiveCallSite
|
||||
not call.asExpr() instanceof SuperCall and
|
||||
// don't flag if there is a receiver object
|
||||
not exists(call.getReceiver())
|
||||
select (FirstLineOf)f, capitalize(f.describe()) + " is invoked as a constructor here $@, " +
|
||||
"and as a normal function here $@.", new, new.toString(), call, call.toString()
|
||||
|
||||
@@ -29,23 +29,11 @@ predicate isFixedArity(Function fn) {
|
||||
*
|
||||
* This is only defined if all potential callees have a fixed arity.
|
||||
*/
|
||||
int maxArity(CallSite invk) {
|
||||
int maxArity(DataFlow::InvokeNode invk) {
|
||||
forall (Function callee | callee = invk.getACallee() | isFixedArity(callee)) and
|
||||
result = max(invk.getACallee().getNumParameter())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if call site `invk` has more arguments than the maximum arity
|
||||
* of any function that it may invoke, and the first of those
|
||||
* arguments is `arg`.
|
||||
*
|
||||
* This predicate is only defined for call sites where callee information is complete.
|
||||
*/
|
||||
predicate firstSpuriousArgument(CallSite invk, Expr arg) {
|
||||
arg = invk.getArgumentNode(maxArity(invk)).asExpr() and
|
||||
not invk.isIncomplete()
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of spurious arguments passed at a call site.
|
||||
*
|
||||
@@ -54,15 +42,18 @@ predicate firstSpuriousArgument(CallSite invk, Expr arg) {
|
||||
* defined to cover all subsequent arguments as well.
|
||||
*/
|
||||
class SpuriousArguments extends Expr {
|
||||
DataFlow::InvokeNode invk;
|
||||
|
||||
SpuriousArguments() {
|
||||
firstSpuriousArgument(_, this)
|
||||
this = invk.getArgument(maxArity(invk)).asExpr() and
|
||||
not invk.isIncomplete()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the call site at which the spurious arguments are passed.
|
||||
*/
|
||||
CallSite getCall() {
|
||||
firstSpuriousArgument(result, this)
|
||||
DataFlow::InvokeNode getCall() {
|
||||
result = invk
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,7 +62,7 @@ class SpuriousArguments extends Expr {
|
||||
* expected by any potential callee.
|
||||
*/
|
||||
int getCount() {
|
||||
result = getCall().(InvokeExpr).getNumArgument() - maxArity(getCall())
|
||||
result = count(int i | exists(invk.getArgument(i)) and i >= maxArity(getCall()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,9 +73,10 @@ class SpuriousArguments extends Expr {
|
||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
||||
*/
|
||||
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
||||
exists (Expr lastArg | lastArg = getCall().(InvokeExpr).getLastArgument() |
|
||||
lastArg.getLocation().hasLocationInfo(_, _, _, endline, endcolumn)
|
||||
getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
||||
exists (DataFlow::Node lastArg |
|
||||
lastArg = max(DataFlow::Node arg, int i | arg = invk.getArgument(i) | arg order by i) |
|
||||
lastArg.hasLocationInfo(_, _, _, endline, endcolumn)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -92,4 +84,4 @@ class SpuriousArguments extends Expr {
|
||||
from SpuriousArguments args, Function f, string arguments
|
||||
where f = args.getCall().getACallee() and
|
||||
if args.getCount() = 1 then arguments = "argument" else arguments = "arguments"
|
||||
select args, "Superfluous " + arguments + " passed to $@.", f, f.describe()
|
||||
select args, "Superfluous " + arguments + " passed to $@.", f, f.describe()
|
||||
|
||||
@@ -14,17 +14,17 @@ import javascript
|
||||
/**
|
||||
* A call that invokes a method on its own receiver.
|
||||
*/
|
||||
class CallOnSelf extends CallExpr {
|
||||
class CallOnSelf extends DataFlow::CallNode {
|
||||
|
||||
CallOnSelf() {
|
||||
exists (Function binder |
|
||||
binder = getEnclosingFunction().getThisBinder() |
|
||||
exists (DataFlow::ThisNode thiz |
|
||||
this = thiz.getAMethodCall(_).asExpr() and
|
||||
this = thiz.getAMethodCall(_) and
|
||||
thiz.getBinder().getAstNode() = binder
|
||||
)
|
||||
or
|
||||
this.(CallSite).getACallee().(ArrowFunctionExpr).getThisBinder() = binder
|
||||
this.getACallee().(ArrowFunctionExpr).getThisBinder() = binder
|
||||
)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ class CallOnSelf extends CallExpr {
|
||||
* Gets a `CallOnSelf` in the callee of this call.
|
||||
*/
|
||||
CallOnSelf getACalleCallOnSelf() {
|
||||
result.getEnclosingFunction() = this.(CallSite).getACallee()
|
||||
result.getEnclosingFunction() = this.getACallee()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -55,15 +55,15 @@ class UnconditionalCallOnSelf extends CallOnSelf {
|
||||
/**
|
||||
* Holds if `call` is guaranteed to occur in its enclosing function, unless an exception occurs.
|
||||
*/
|
||||
predicate isUnconditionalCall(CallExpr call) {
|
||||
predicate isUnconditionalCall(DataFlow::CallNode call) {
|
||||
exists (ReachableBasicBlock callBlock, ReachableBasicBlock entryBlock |
|
||||
callBlock.postDominates(entryBlock) and
|
||||
callBlock.getANode() = call and
|
||||
callBlock = call.getBasicBlock() and
|
||||
entryBlock = call.getEnclosingFunction().getEntryBB()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isStateUpdateMethodCall(MethodCallExpr mce) {
|
||||
predicate isStateUpdateMethodCall(DataFlow::MethodCallNode mce) {
|
||||
exists (string updateMethodName |
|
||||
updateMethodName = "setState" or
|
||||
updateMethodName = "replaceState" or
|
||||
@@ -111,7 +111,8 @@ class StateUpdateVolatileMethod extends Function {
|
||||
|
||||
}
|
||||
|
||||
from StateUpdateVolatileMethod root, CallOnSelf initCall, MethodCallExpr stateUpdate, string callDescription
|
||||
from StateUpdateVolatileMethod root, CallOnSelf initCall, DataFlow::MethodCallNode stateUpdate,
|
||||
string callDescription
|
||||
where initCall.getEnclosingFunction() = root and
|
||||
stateUpdate = initCall.getACalleCallOnSelf*() and
|
||||
isStateUpdateMethodCall(stateUpdate) and
|
||||
|
||||
@@ -55,9 +55,9 @@ int numRet(Function f) {
|
||||
*/
|
||||
predicate isDualUseConstructor(Function f) {
|
||||
numRet(f) = 1 and
|
||||
exists (ReturnStmt ret, NewExpr new | ret.getContainer() = f |
|
||||
new = ret.getExpr().stripParens() and
|
||||
new.(CallSite).getACallee() = f
|
||||
exists (ReturnStmt ret, DataFlow::NewNode new | ret.getContainer() = f |
|
||||
new.asExpr() = ret.getExpr().stripParens() and
|
||||
new.getACallee() = f
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class CallToObjectDefineProperty extends DataFlow::MethodCallNode {
|
||||
CallToObjectDefineProperty() {
|
||||
exists (GlobalVariable obj |
|
||||
obj.getName() = "Object" and
|
||||
astNode.calls(obj.getAnAccess(), "defineProperty")
|
||||
calls(DataFlow::valueNode(obj.getAnAccess()), "defineProperty")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@ import javascript
|
||||
private import InferredTypes
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `DataFlow::InvokeNode` instead.
|
||||
*
|
||||
* A function call or `new` expression, with information about its potential callees.
|
||||
*
|
||||
* Both direct calls and reflective calls using `call` or `apply` are modelled.
|
||||
*/
|
||||
class CallSite extends @invokeexpr {
|
||||
deprecated class CallSite extends @invokeexpr {
|
||||
InvokeExpr invk;
|
||||
|
||||
CallSite() { invk = this }
|
||||
@@ -120,7 +122,7 @@ class CallSite extends @invokeexpr {
|
||||
/**
|
||||
* A reflective function call using `call` or `apply`.
|
||||
*/
|
||||
class ReflectiveCallSite extends CallSite {
|
||||
deprecated class ReflectiveCallSite extends CallSite {
|
||||
DataFlow::AnalyzedNode callee;
|
||||
string callMode;
|
||||
|
||||
|
||||
@@ -407,7 +407,7 @@ private predicate callInputStep(Function f, DataFlow::Node invk,
|
||||
or
|
||||
exists (SsaDefinition prevDef, SsaDefinition def |
|
||||
pred = DataFlow::ssaDefinitionNode(prevDef) and
|
||||
calls(invk.asExpr(), f) and captures(f, prevDef, def) and
|
||||
calls(invk, f) and captures(f, prevDef, def) and
|
||||
succ = DataFlow::ssaDefinitionNode(def)
|
||||
)
|
||||
) and
|
||||
|
||||
@@ -29,6 +29,9 @@ module DataFlow {
|
||||
or TDestructuringPatternNode(DestructuringPattern dp)
|
||||
or TElementPatternNode(ArrayPattern ap, Expr p) { p = ap.getElement(_) }
|
||||
or TElementNode(ArrayExpr arr, Expr e) { e = arr.getAnElement() }
|
||||
or TReflectiveCallNode(MethodCallExpr ce, string kind) {
|
||||
ce.getMethodName() = kind and (kind = "call" or kind = "apply")
|
||||
}
|
||||
|
||||
/**
|
||||
* A node in the data flow graph.
|
||||
@@ -366,6 +369,30 @@ module DataFlow {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node in the data flow graph which corresponds to the reflective call performed
|
||||
* by a `.call` or `.apply` invocation.
|
||||
*/
|
||||
private class ReflectiveCallNode extends Node, TReflectiveCallNode {
|
||||
MethodCallExpr call;
|
||||
string kind;
|
||||
|
||||
ReflectiveCallNode() { this = TReflectiveCallNode(call, kind) }
|
||||
|
||||
override BasicBlock getBasicBlock() {
|
||||
result = call.getBasicBlock()
|
||||
}
|
||||
|
||||
override predicate hasLocationInfo(string filepath, int startline, int startcolumn,
|
||||
int endline, int endcolumn) {
|
||||
call.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "reflective call"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node that reads or writes an object property or class member.
|
||||
*
|
||||
@@ -643,6 +670,146 @@ module DataFlow {
|
||||
override string getPropertyName() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes representing various kinds of calls.
|
||||
*
|
||||
* Subclass the classes in this module to introduce new kinds of calls. If you want to
|
||||
* refine the behaviour of the analysis on existing kinds of calls, subclass `InvokeNode`
|
||||
* instead.
|
||||
*/
|
||||
module Impl {
|
||||
/**
|
||||
* A data flow node representing a function invocation, either explicitly or reflectively,
|
||||
* and either with or without `new`.
|
||||
*/
|
||||
abstract class InvokeNodeDef extends DataFlow::Node {
|
||||
/** Gets the name of the function or method being invoked, if it can be determined. */
|
||||
abstract string getCalleeName();
|
||||
|
||||
/** Gets the data flow node specifying the function to be called. */
|
||||
abstract DataFlow::Node getCalleeNode();
|
||||
|
||||
/** Gets the data flow node corresponding to the `i`th argument of this invocation. */
|
||||
abstract DataFlow::Node getArgument(int i);
|
||||
|
||||
/** Gets the data flow node corresponding to an argument of this invocation. */
|
||||
abstract DataFlow::Node getAnArgument();
|
||||
|
||||
/** Gets the number of arguments of this invocation, if it can be determined. */
|
||||
abstract int getNumArgument();
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing a function call without `new`, either explicitly or
|
||||
* reflectively.
|
||||
*/
|
||||
abstract class CallNodeDef extends InvokeNodeDef {
|
||||
/** Gets the data flow node corresponding to the receiver of this call, if any. */
|
||||
DataFlow::Node getReceiver() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing a method call.
|
||||
*/
|
||||
abstract class MethodCallNodeDef extends CallNodeDef {
|
||||
/** Gets the name of the method being invoked, if it can be determined. */
|
||||
abstract string getMethodName();
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing a function invocation with `new`.
|
||||
*/
|
||||
abstract class NewNodeDef extends InvokeNodeDef {
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing an explicit (that is, non-reflective) function invocation.
|
||||
*/
|
||||
class ExplicitInvokeNode extends InvokeNodeDef, DataFlow::ValueNode {
|
||||
override InvokeExpr astNode;
|
||||
|
||||
override string getCalleeName() {
|
||||
result = astNode.getCalleeName()
|
||||
}
|
||||
|
||||
override DataFlow::Node getCalleeNode() {
|
||||
result = DataFlow::valueNode(astNode.getCallee())
|
||||
}
|
||||
|
||||
override DataFlow::Node getArgument(int i) {
|
||||
not astNode.isSpreadArgument([0..i]) and result = DataFlow::valueNode(astNode.getArgument(i))
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() {
|
||||
exists (Expr arg | arg = astNode.getAnArgument() |
|
||||
not arg instanceof SpreadElement and
|
||||
result = DataFlow::valueNode(arg)
|
||||
)
|
||||
}
|
||||
|
||||
override int getNumArgument() {
|
||||
not astNode.isSpreadArgument(_) and result = astNode.getNumArgument()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing an explicit (that is, non-reflective) function call.
|
||||
*/
|
||||
private class ExplicitCallNode extends CallNodeDef, ExplicitInvokeNode {
|
||||
override CallExpr astNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing an explicit (that is, non-reflective) method call.
|
||||
*/
|
||||
private class ExplicitMethodCallNode extends MethodCallNodeDef, ExplicitCallNode {
|
||||
override MethodCallExpr astNode;
|
||||
override DataFlow::Node getReceiver() { result = DataFlow::valueNode(astNode.getReceiver()) }
|
||||
override string getMethodName() { result = astNode.getMethodName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing a `new` expression.
|
||||
*/
|
||||
private class ExplicitNewNode extends NewNodeDef, ExplicitInvokeNode {
|
||||
override NewExpr astNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing a reflective function call.
|
||||
*/
|
||||
private class ReflectiveCallNodeDef extends CallNodeDef {
|
||||
ExplicitMethodCallNode originalCall;
|
||||
string kind;
|
||||
|
||||
ReflectiveCallNodeDef() {
|
||||
this = TReflectiveCallNode(originalCall.asExpr(), kind)
|
||||
}
|
||||
|
||||
override string getCalleeName() { none() }
|
||||
|
||||
override DataFlow::Node getCalleeNode() {
|
||||
result = originalCall.getReceiver()
|
||||
}
|
||||
|
||||
override DataFlow::Node getReceiver() {
|
||||
result = originalCall.getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getArgument(int i) {
|
||||
i >= 0 and kind = "call" and result = originalCall.getArgument(i+1)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() {
|
||||
kind = "call" and result = originalCall.getAnArgument() and result != getReceiver()
|
||||
}
|
||||
|
||||
override int getNumArgument() {
|
||||
result >= 0 and kind = "call" and result = originalCall.getNumArgument()-1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An array element viewed as a property write; for instance, in
|
||||
* `var arr = ["first", , "third"]`, `"first"` is a write of property 0 of `arr`
|
||||
|
||||
@@ -20,32 +20,67 @@ class ParameterNode extends DataFlow::DefaultSourceNode {
|
||||
}
|
||||
|
||||
/** A data flow node corresponding to a function invocation (with or without `new`). */
|
||||
class InvokeNode extends DataFlow::ValueNode, DataFlow::DefaultSourceNode {
|
||||
override InvokeExpr astNode;
|
||||
class InvokeNode extends DataFlow::DefaultSourceNode {
|
||||
DataFlow::Impl::InvokeNodeDef impl;
|
||||
|
||||
InvokeNode() { this = impl }
|
||||
|
||||
/** Gets the name of the function or method being invoked, if it can be determined. */
|
||||
string getCalleeName() {
|
||||
result = astNode.getCalleeName()
|
||||
result = impl.getCalleeName()
|
||||
}
|
||||
|
||||
/** DEPRECATED: Use `getCalleeNode()` instead. */
|
||||
deprecated
|
||||
DataFlow::Node getCallee() {
|
||||
result = getCalleeNode()
|
||||
}
|
||||
|
||||
/** Gets the data flow node specifying the function to be called. */
|
||||
DataFlow::ValueNode getCallee() {
|
||||
result = DataFlow::valueNode(astNode.getCallee())
|
||||
DataFlow::Node getCalleeNode() {
|
||||
result = impl.getCalleeNode()
|
||||
}
|
||||
|
||||
/** Gets the data flow node corresponding to the `i`th argument of this invocation. */
|
||||
DataFlow::ValueNode getArgument(int i) {
|
||||
result = DataFlow::valueNode(astNode.getArgument(i))
|
||||
/**
|
||||
* Gets the data flow node corresponding to the `i`th argument of this invocation.
|
||||
*
|
||||
* For direct calls, this is the `i`th argument to the call itself: for instance,
|
||||
* for a call `f(x, y)`, the 0th argument node is `x` and the first argument node is `y`.
|
||||
*
|
||||
* For reflective calls using `call`, the 0th argument to the call denotes the
|
||||
* receiver, so argument positions are shifted by one: for instance, for a call
|
||||
* `f.call(x, y, z)`, the 0th argument node is `y` and the first argument node is `z`,
|
||||
* while `x` is not an argument node at all.
|
||||
*
|
||||
* For reflective calls using `apply` we cannot, in general, tell which argument
|
||||
* occurs at which position, so this predicate is not defined for such calls.
|
||||
*
|
||||
* Note that this predicate is not defined for arguments following a spread
|
||||
* argument: for instance, for a call `f(x, ...y, z)`, the 0th argument node is `x`,
|
||||
* but the position of `z` cannot be determined, hence there are no first and second
|
||||
* argument nodes.
|
||||
*/
|
||||
DataFlow::Node getArgument(int i) {
|
||||
result = impl.getArgument(i)
|
||||
}
|
||||
|
||||
/** Gets the data flow node corresponding to an argument of this invocation. */
|
||||
DataFlow::ValueNode getAnArgument() {
|
||||
result = getArgument(_)
|
||||
DataFlow::Node getAnArgument() {
|
||||
result = impl.getAnArgument()
|
||||
}
|
||||
|
||||
/** Gets the number of arguments of this invocation. */
|
||||
/** Gets the data flow node corresponding to the last argument of this invocation. */
|
||||
DataFlow::Node getLastArgument() {
|
||||
result = getArgument(getNumArgument()-1)
|
||||
}
|
||||
|
||||
/** Gets the number of arguments of this invocation, if it can be determined. */
|
||||
int getNumArgument() {
|
||||
result = astNode.getNumArgument()
|
||||
result = impl.getNumArgument()
|
||||
}
|
||||
|
||||
Function getEnclosingFunction() {
|
||||
result = getBasicBlock().getContainer()
|
||||
}
|
||||
|
||||
/** Gets a function passed as the `i`th argument of this invocation. */
|
||||
@@ -63,16 +98,73 @@ class InvokeNode extends DataFlow::ValueNode, DataFlow::DefaultSourceNode {
|
||||
obj.hasPropertyWrite(name, result)
|
||||
)
|
||||
}
|
||||
|
||||
/** 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()
|
||||
}
|
||||
|
||||
/** 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()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the approximation of possible callees for this call site is
|
||||
* affected by the given analysis incompleteness `cause`.
|
||||
*/
|
||||
predicate isIndefinite(DataFlow::Incompleteness cause) {
|
||||
getACalleeValue().isIndefinite(cause)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if our approximation of possible callees for this call site is
|
||||
* likely to be imprecise.
|
||||
*
|
||||
* We currently track one specific source of imprecision: call
|
||||
* resolution relies on flow through global variables, and the flow
|
||||
* analysis finds possible callees that are not functions.
|
||||
* This usually means that a global variable is used in multiple
|
||||
* independent contexts, so tracking flow through it leads to
|
||||
* imprecision.
|
||||
*/
|
||||
predicate isImprecise() {
|
||||
isIndefinite("global") and
|
||||
exists (DefiniteAbstractValue v | v = getACalleeValue() |
|
||||
not v instanceof AbstractCallable
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if our approximation of possible callees for this call site is
|
||||
* likely to be incomplete.
|
||||
*/
|
||||
predicate isIncomplete() {
|
||||
// the flow analysis identifies a source of incompleteness other than
|
||||
// global flow (which usually leads to imprecision rather than incompleteness)
|
||||
any (DataFlow::Incompleteness cause | isIndefinite(cause)) != "global"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if our approximation of possible callees for this call site is
|
||||
* likely to be imprecise or incomplete.
|
||||
*/
|
||||
predicate isUncertain() {
|
||||
isImprecise() or isIncomplete()
|
||||
}
|
||||
}
|
||||
|
||||
/** A data flow node corresponding to a function call without `new`. */
|
||||
class CallNode extends InvokeNode {
|
||||
override CallExpr astNode;
|
||||
}
|
||||
|
||||
/** A data flow node corresponding to a method call. */
|
||||
class MethodCallNode extends CallNode {
|
||||
override MethodCallExpr astNode;
|
||||
override DataFlow::Impl::CallNodeDef impl;
|
||||
|
||||
/**
|
||||
* Gets the data flow node corresponding to the receiver expression of this method call.
|
||||
@@ -80,11 +172,16 @@ class MethodCallNode extends CallNode {
|
||||
* For example, the receiver of `x.m()` is `x`.
|
||||
*/
|
||||
DataFlow::Node getReceiver() {
|
||||
result = DataFlow::valueNode(astNode.getReceiver())
|
||||
result = impl.getReceiver()
|
||||
}
|
||||
}
|
||||
|
||||
/** A data flow node corresponding to a method call. */
|
||||
class MethodCallNode extends CallNode {
|
||||
override DataFlow::Impl::MethodCallNodeDef impl;
|
||||
|
||||
/** Gets the name of the invoked method, if it can be determined. */
|
||||
string getMethodName() { result = astNode.getMethodName() }
|
||||
string getMethodName() { result = impl.getMethodName() }
|
||||
|
||||
/**
|
||||
* Holds if this data flow node calls method `methodName` on receiver node `receiver`.
|
||||
@@ -98,7 +195,7 @@ class MethodCallNode extends CallNode {
|
||||
|
||||
/** A data flow node corresponding to a `new` expression. */
|
||||
class NewNode extends InvokeNode {
|
||||
override NewExpr astNode;
|
||||
override DataFlow::Impl::NewNodeDef impl;
|
||||
}
|
||||
|
||||
/** A data flow node corresponding to a `this` expression. */
|
||||
|
||||
@@ -125,7 +125,7 @@ abstract class SourceNode extends DataFlow::Node {
|
||||
*/
|
||||
DataFlow::CallNode getAMethodCall(string methodName) {
|
||||
exists (PropAccess pacc |
|
||||
pacc = result.getCallee().asExpr().stripParens() and
|
||||
pacc = result.getCalleeNode().asExpr().stripParens() and
|
||||
flowsToExpr(pacc.getBase()) and
|
||||
pacc.getPropertyName() = methodName
|
||||
)
|
||||
@@ -142,7 +142,7 @@ abstract class SourceNode extends DataFlow::Node {
|
||||
* Gets an invocation (with our without `new`) of this node.
|
||||
*/
|
||||
DataFlow::InvokeNode getAnInvocation() {
|
||||
flowsTo(result.getCallee())
|
||||
flowsTo(result.getCalleeNode())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,7 +182,6 @@ class DefaultSourceNode extends SourceNode {
|
||||
astNode instanceof PropAccess or
|
||||
astNode instanceof Function or
|
||||
astNode instanceof ClassDefinition or
|
||||
astNode instanceof InvokeExpr or
|
||||
astNode instanceof ObjectExpr or
|
||||
astNode instanceof ArrayExpr or
|
||||
astNode instanceof JSXNode or
|
||||
@@ -197,5 +196,7 @@ class DefaultSourceNode extends SourceNode {
|
||||
)
|
||||
or
|
||||
DataFlow::parameterNode(this, _)
|
||||
or
|
||||
this instanceof DataFlow::Impl::InvokeNodeDef
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ private module NodeTracking {
|
||||
or
|
||||
exists (SsaDefinition prevDef, SsaDefinition def |
|
||||
pred = DataFlow::ssaDefinitionNode(prevDef) and
|
||||
calls(invk.asExpr(), f) and captures(f, prevDef, def) and
|
||||
calls(invk, f) and captures(f, prevDef, def) and
|
||||
succ = DataFlow::ssaDefinitionNode(def)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -20,13 +20,11 @@ predicate shouldTrackProperties(AbstractValue obj) {
|
||||
/**
|
||||
* Holds if `invk` may invoke `f`.
|
||||
*/
|
||||
predicate calls(InvokeExpr invk, Function f) {
|
||||
exists (CallSite cs | cs = invk |
|
||||
if cs.isIndefinite("global") then
|
||||
(f = cs.getACallee() and f.getFile() = invk.getFile())
|
||||
else
|
||||
f = cs.getACallee()
|
||||
)
|
||||
predicate calls(DataFlow::InvokeNode invk, Function f) {
|
||||
if invk.isIndefinite("global") then
|
||||
(f = invk.getACallee() and f.getFile() = invk.getFile())
|
||||
else
|
||||
f = invk.getACallee()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,11 +63,11 @@ predicate localFlowStep(DataFlow::Node pred, DataFlow::Node succ,
|
||||
* Holds if `arg` is passed as an argument into parameter `parm`
|
||||
* through invocation `invk` of function `f`.
|
||||
*/
|
||||
predicate argumentPassing(DataFlow::ValueNode invk, DataFlow::ValueNode arg, Function f, Parameter parm) {
|
||||
exists (int i, CallSite cs |
|
||||
cs = invk.asExpr() and calls(cs, f) and
|
||||
predicate argumentPassing(DataFlow::InvokeNode invk, DataFlow::ValueNode arg, Function f, Parameter parm) {
|
||||
calls(invk, f) and
|
||||
exists (int i |
|
||||
f.getParameter(i) = parm and not parm.isRestParameter() and
|
||||
arg = cs.getArgumentNode(i)
|
||||
arg = invk.getArgument(i)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -92,7 +90,7 @@ predicate callStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
predicate returnStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists (Function f |
|
||||
returnExpr(f, pred, _) and
|
||||
calls(succ.asExpr(), f)
|
||||
calls(succ, f)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ module ConnectExpressShared {
|
||||
// heuristic: does not return anything (the server will not use the return value)
|
||||
exists(astNode.getAReturnStmt().getExpr()) or
|
||||
// heuristic: is not invoked (the server invokes this at a call site we cannot reason precisely about)
|
||||
exists(CallSite cs | cs.getACallee() = astNode)
|
||||
exists(DataFlow::InvokeNode cs | cs.getACallee() = astNode)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -424,7 +424,7 @@ module NodeJSLib {
|
||||
// heuristic: does not return anything (Node.js will not use the return value)
|
||||
exists(astNode.getAReturnStmt().getExpr()) or
|
||||
// heuristic: is not invoked (Node.js invokes this at a call site we cannot reason precisely about)
|
||||
exists(CallSite cs | cs.getACallee() = astNode)
|
||||
exists(DataFlow::InvokeNode cs | cs.getACallee() = astNode)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -192,10 +192,8 @@ abstract class ReactComponent extends ASTNode {
|
||||
* constructor of this component.
|
||||
*/
|
||||
DataFlow::SourceNode getACandidatePropsSource() {
|
||||
exists (DataFlow::InvokeNode call |
|
||||
getComponentCreatorSource().flowsTo(call.getCallee()) and
|
||||
result.flowsTo(call.getArgument(0))
|
||||
) or
|
||||
result.flowsTo(getComponentCreatorSource().getAnInvocation().getArgument(0))
|
||||
or
|
||||
result = getADefaultPropsSource()
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ abstract class SensitiveAction extends DataFlow::Node { }
|
||||
class AuthorizationCall extends SensitiveAction, DataFlow::CallNode {
|
||||
|
||||
AuthorizationCall() {
|
||||
exists(string s | s = astNode.getCalleeName() |
|
||||
exists(string s | s = getCalleeName() |
|
||||
// name contains `login` or `auth`, but not as part of `loginfo` or `unauth`;
|
||||
// also exclude `author`
|
||||
s.regexpMatch("(?i).*(login(?!fo)|(?<!un)auth(?!or\\b)).*") and
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import javascript
|
||||
|
||||
from CallSite c
|
||||
select c, c.getACallee()
|
||||
@@ -26,4 +26,11 @@ class OtherSub extends PseudoClass {
|
||||
super();
|
||||
console.log(this.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sum(x, y, z) {
|
||||
return x+y+z;
|
||||
}
|
||||
sum(...[1, 2, 3]);
|
||||
sum(1, ...[2, 3]);
|
||||
sum(1, ...[2], 3);
|
||||
|
||||
@@ -9,10 +9,16 @@
|
||||
| es2015.js:10:5:10:22 | arguments.callee() | es2015.js:8:2:12:1 | functio ... \\n };\\n} |
|
||||
| es2015.js:16:5:16:11 | super() | es2015.js:2:14:4:3 | () {\\n ... ");\\n } |
|
||||
| es2015.js:26:5:26:11 | super() | es2015.js:20:1:22:1 | functio ... = 42;\\n} |
|
||||
| es2015.js:34:1:34:17 | sum(...[1, 2, 3]) | es2015.js:31:1:33:1 | functio ... +y+z;\\n} |
|
||||
| es2015.js:35:1:35:17 | sum(1, ...[2, 3]) | es2015.js:31:1:33:1 | functio ... +y+z;\\n} |
|
||||
| es2015.js:36:1:36:17 | sum(1, ...[2], 3) | es2015.js:31:1:33:1 | functio ... +y+z;\\n} |
|
||||
| m.js:2:1:2:11 | exports.f() | m.js:1:13:1:25 | function() {} |
|
||||
| m.js:3:1:3:18 | module.exports.f() | m.js:1:13:1:25 | function() {} |
|
||||
| n.js:2:1:2:5 | m.f() | m.js:1:13:1:25 | function() {} |
|
||||
| n.js:5:1:5:6 | m2.f() | m2.js:2:6:2:18 | function() {} |
|
||||
| reflection.js:7:1:7:22 | reflective call | reflection.js:1:1:3:1 | functio ... x+y;\\n} |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:5:15:5:39 | functio ... n 56; } |
|
||||
| reflection.js:8:1:8:25 | reflective call | reflection.js:1:1:3:1 | functio ... x+y;\\n} |
|
||||
| tst.js:6:1:6:3 | f() | tst.js:1:1:1:15 | function f() {} |
|
||||
| tst.js:7:1:7:3 | g() | tst.js:2:9:2:21 | function() {} |
|
||||
| tst.js:8:1:8:3 | h() | tst.js:3:5:3:17 | function() {} |
|
||||
@@ -38,3 +44,5 @@
|
||||
| tst.js:60:15:60:21 | new A() | tst.js:44:1:44:15 | function A() {} |
|
||||
| tst.js:64:13:64:19 | new B() | tst.js:50:1:50:15 | function B() {} |
|
||||
| tst.js:66:5:66:9 | b.f() | tst.js:65:11:65:23 | function() {} |
|
||||
| tst.js:69:1:69:10 | globalfn() | tst3.js:1:1:1:22 | functio ... fn() {} |
|
||||
| tst.js:70:1:70:11 | globalfn2() | tst3.js:2:1:2:23 | functio ... n2() {} |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode c
|
||||
select c, c.getACallee()
|
||||
@@ -0,0 +1,18 @@
|
||||
| classes.js:4:7:4:26 | console.log("Hello") | classes.js:4:19:4:25 | "Hello" |
|
||||
| classes.js:14:7:14:27 | console ... ello!") | classes.js:14:19:14:26 | "Hello!" |
|
||||
| es2015.js:3:5:3:21 | console.log("hi") | es2015.js:3:17:3:20 | "hi" |
|
||||
| es2015.js:27:5:27:23 | console.log(this.x) | es2015.js:27:17:27:22 | this.x |
|
||||
| es2015.js:35:1:35:17 | sum(1, ...[2, 3]) | es2015.js:35:5:35:5 | 1 |
|
||||
| es2015.js:36:1:36:17 | sum(1, ...[2], 3) | es2015.js:36:5:36:5 | 1 |
|
||||
| es2015.js:36:1:36:17 | sum(1, ...[2], 3) | es2015.js:36:16:36:16 | 3 |
|
||||
| n.js:1:9:1:22 | require('./m') | n.js:1:17:1:21 | './m' |
|
||||
| n.js:4:10:4:24 | require('./m2') | n.js:4:18:4:23 | './m2' |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:10:7:13 | null |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:16:7:17 | 23 |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:20:7:21 | 19 |
|
||||
| reflection.js:7:1:7:22 | reflective call | reflection.js:7:16:7:17 | 23 |
|
||||
| reflection.js:7:1:7:22 | reflective call | reflection.js:7:20:7:21 | 19 |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:11:8:14 | null |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:17:8:24 | [23, 19] |
|
||||
| tst.js:22:1:22:4 | l(k) | tst.js:22:3:22:3 | k |
|
||||
| tst.js:42:2:42:29 | functio ... x; }(o) | tst.js:42:28:42:28 | o |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode invk
|
||||
select invk, invk.getAnArgument()
|
||||
@@ -0,0 +1,17 @@
|
||||
| classes.js:4:7:4:26 | console.log("Hello") | 0 | classes.js:4:19:4:25 | "Hello" |
|
||||
| classes.js:14:7:14:27 | console ... ello!") | 0 | classes.js:14:19:14:26 | "Hello!" |
|
||||
| es2015.js:3:5:3:21 | console.log("hi") | 0 | es2015.js:3:17:3:20 | "hi" |
|
||||
| es2015.js:27:5:27:23 | console.log(this.x) | 0 | es2015.js:27:17:27:22 | this.x |
|
||||
| es2015.js:35:1:35:17 | sum(1, ...[2, 3]) | 0 | es2015.js:35:5:35:5 | 1 |
|
||||
| es2015.js:36:1:36:17 | sum(1, ...[2], 3) | 0 | es2015.js:36:5:36:5 | 1 |
|
||||
| n.js:1:9:1:22 | require('./m') | 0 | n.js:1:17:1:21 | './m' |
|
||||
| n.js:4:10:4:24 | require('./m2') | 0 | n.js:4:18:4:23 | './m2' |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | 0 | reflection.js:7:10:7:13 | null |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | 1 | reflection.js:7:16:7:17 | 23 |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | 2 | reflection.js:7:20:7:21 | 19 |
|
||||
| reflection.js:7:1:7:22 | reflective call | 0 | reflection.js:7:16:7:17 | 23 |
|
||||
| reflection.js:7:1:7:22 | reflective call | 1 | reflection.js:7:20:7:21 | 19 |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | 0 | reflection.js:8:11:8:14 | null |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | 1 | reflection.js:8:17:8:24 | [23, 19] |
|
||||
| tst.js:22:1:22:4 | l(k) | 0 | tst.js:22:3:22:3 | k |
|
||||
| tst.js:42:2:42:29 | functio ... x; }(o) | 0 | tst.js:42:28:42:28 | o |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode invk, int i
|
||||
select invk, i, invk.getArgument(i)
|
||||
@@ -0,0 +1,49 @@
|
||||
| a.js:2:1:2:5 | foo() | foo |
|
||||
| a.js:3:1:3:5 | bar() | bar |
|
||||
| a.js:4:1:4:5 | qux() | qux |
|
||||
| a.js:7:1:7:5 | baz() | baz |
|
||||
| classes.js:4:7:4:26 | console.log("Hello") | log |
|
||||
| classes.js:8:7:8:18 | this.hello() | hello |
|
||||
| classes.js:14:7:14:27 | console ... ello!") | log |
|
||||
| classes.js:18:3:18:9 | new B() | B |
|
||||
| classes.js:18:3:18:17 | new B().hello() | hello |
|
||||
| es2015.js:3:5:3:21 | console.log("hi") | log |
|
||||
| es2015.js:6:1:6:18 | new ExampleClass() | ExampleClass |
|
||||
| es2015.js:10:5:10:22 | arguments.callee() | callee |
|
||||
| es2015.js:27:5:27:23 | console.log(this.x) | log |
|
||||
| es2015.js:34:1:34:17 | sum(...[1, 2, 3]) | sum |
|
||||
| es2015.js:35:1:35:17 | sum(1, ...[2, 3]) | sum |
|
||||
| es2015.js:36:1:36:17 | sum(1, ...[2], 3) | sum |
|
||||
| m.js:2:1:2:11 | exports.f() | f |
|
||||
| m.js:3:1:3:18 | module.exports.f() | f |
|
||||
| n.js:1:9:1:22 | require('./m') | require |
|
||||
| n.js:2:1:2:5 | m.f() | f |
|
||||
| n.js:4:10:4:24 | require('./m2') | require |
|
||||
| n.js:5:1:5:6 | m2.f() | f |
|
||||
| reflection.js:4:5:4:12 | sneaky() | sneaky |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | call |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | apply |
|
||||
| tst.js:6:1:6:3 | f() | f |
|
||||
| tst.js:7:1:7:3 | g() | g |
|
||||
| tst.js:8:1:8:3 | h() | h |
|
||||
| tst.js:9:1:9:3 | k() | k |
|
||||
| tst.js:14:2:14:4 | m() | m |
|
||||
| tst.js:15:2:15:4 | l() | l |
|
||||
| tst.js:16:2:16:19 | arguments.callee() | callee |
|
||||
| tst.js:17:2:17:4 | n() | n |
|
||||
| tst.js:18:2:18:4 | p() | p |
|
||||
| tst.js:19:2:19:4 | f() | f |
|
||||
| tst.js:22:1:22:4 | l(k) | l |
|
||||
| tst.js:24:1:24:7 | new f() | f |
|
||||
| tst.js:25:1:25:5 | new g | g |
|
||||
| tst.js:33:4:33:11 | this.g() | g |
|
||||
| tst.js:41:1:41:5 | o.f() | f |
|
||||
| tst.js:42:1:42:34 | (functi ... o)).f() | f |
|
||||
| tst.js:46:2:46:9 | this.g() | g |
|
||||
| tst.js:53:3:53:10 | this.g() | g |
|
||||
| tst.js:56:17:56:29 | Math.random() | random |
|
||||
| tst.js:60:15:60:21 | new A() | A |
|
||||
| tst.js:64:13:64:19 | new B() | B |
|
||||
| tst.js:66:5:66:9 | b.f() | f |
|
||||
| tst.js:69:1:69:10 | globalfn() | globalfn |
|
||||
| tst.js:70:1:70:11 | globalfn2() | globalfn2 |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode invk
|
||||
select invk, invk.getCalleeName()
|
||||
@@ -0,0 +1,57 @@
|
||||
| a.js:2:1:2:5 | foo() | a.js:2:1:2:3 | foo |
|
||||
| a.js:3:1:3:5 | bar() | a.js:3:1:3:3 | bar |
|
||||
| a.js:4:1:4:5 | qux() | a.js:4:1:4:3 | qux |
|
||||
| a.js:7:1:7:5 | baz() | a.js:7:1:7:3 | baz |
|
||||
| classes.js:4:7:4:26 | console.log("Hello") | classes.js:4:7:4:17 | console.log |
|
||||
| classes.js:8:7:8:18 | this.hello() | classes.js:8:7:8:16 | this.hello |
|
||||
| classes.js:12:21:12:20 | super(...args) | classes.js:12:21:12:20 | super |
|
||||
| classes.js:14:7:14:27 | console ... ello!") | classes.js:14:7:14:17 | console.log |
|
||||
| classes.js:18:3:18:9 | new B() | classes.js:18:7:18:7 | B |
|
||||
| classes.js:18:3:18:17 | new B().hello() | classes.js:18:3:18:15 | new B().hello |
|
||||
| es2015.js:3:5:3:21 | console.log("hi") | es2015.js:3:5:3:15 | console.log |
|
||||
| es2015.js:6:1:6:18 | new ExampleClass() | es2015.js:6:5:6:16 | ExampleClass |
|
||||
| es2015.js:10:5:10:22 | arguments.callee() | es2015.js:10:5:10:20 | arguments.callee |
|
||||
| es2015.js:16:5:16:11 | super() | es2015.js:16:5:16:9 | super |
|
||||
| es2015.js:26:5:26:11 | super() | es2015.js:26:5:26:9 | super |
|
||||
| es2015.js:27:5:27:23 | console.log(this.x) | es2015.js:27:5:27:15 | console.log |
|
||||
| es2015.js:34:1:34:17 | sum(...[1, 2, 3]) | es2015.js:34:1:34:3 | sum |
|
||||
| es2015.js:35:1:35:17 | sum(1, ...[2, 3]) | es2015.js:35:1:35:3 | sum |
|
||||
| es2015.js:36:1:36:17 | sum(1, ...[2], 3) | es2015.js:36:1:36:3 | sum |
|
||||
| m.js:2:1:2:11 | exports.f() | m.js:2:1:2:9 | exports.f |
|
||||
| m.js:3:1:3:18 | module.exports.f() | m.js:3:1:3:16 | module.exports.f |
|
||||
| n.js:1:9:1:22 | require('./m') | n.js:1:9:1:15 | require |
|
||||
| n.js:2:1:2:5 | m.f() | n.js:2:1:2:3 | m.f |
|
||||
| n.js:4:10:4:24 | require('./m2') | n.js:4:10:4:16 | require |
|
||||
| n.js:5:1:5:6 | m2.f() | n.js:5:1:5:4 | m2.f |
|
||||
| reflection.js:4:5:4:12 | sneaky() | reflection.js:4:5:4:10 | sneaky |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:1:7:8 | add.call |
|
||||
| reflection.js:7:1:7:22 | reflective call | reflection.js:7:1:7:3 | add |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:1:8:9 | add.apply |
|
||||
| reflection.js:8:1:8:25 | reflective call | reflection.js:8:1:8:3 | add |
|
||||
| tst.js:6:1:6:3 | f() | tst.js:6:1:6:1 | f |
|
||||
| tst.js:7:1:7:3 | g() | tst.js:7:1:7:1 | g |
|
||||
| tst.js:8:1:8:3 | h() | tst.js:8:1:8:1 | h |
|
||||
| tst.js:9:1:9:3 | k() | tst.js:9:1:9:1 | k |
|
||||
| tst.js:14:2:14:4 | m() | tst.js:14:2:14:2 | m |
|
||||
| tst.js:15:2:15:4 | l() | tst.js:15:2:15:2 | l |
|
||||
| tst.js:16:2:16:19 | arguments.callee() | tst.js:16:2:16:17 | arguments.callee |
|
||||
| tst.js:17:2:17:4 | n() | tst.js:17:2:17:2 | n |
|
||||
| tst.js:18:2:18:4 | p() | tst.js:18:2:18:2 | p |
|
||||
| tst.js:19:2:19:4 | f() | tst.js:19:2:19:2 | f |
|
||||
| tst.js:22:1:22:4 | l(k) | tst.js:22:1:22:1 | l |
|
||||
| tst.js:24:1:24:7 | new f() | tst.js:24:5:24:5 | f |
|
||||
| tst.js:25:1:25:5 | new g | tst.js:25:5:25:5 | g |
|
||||
| tst.js:27:1:27:16 | (function(){})() | tst.js:27:1:27:14 | (function(){}) |
|
||||
| tst.js:28:2:28:15 | function(){}() | tst.js:28:2:28:13 | function(){} |
|
||||
| tst.js:33:4:33:11 | this.g() | tst.js:33:4:33:9 | this.g |
|
||||
| tst.js:41:1:41:5 | o.f() | tst.js:41:1:41:3 | o.f |
|
||||
| tst.js:42:1:42:34 | (functi ... o)).f() | tst.js:42:1:42:32 | (functi ... }(o)).f |
|
||||
| tst.js:42:2:42:29 | functio ... x; }(o) | tst.js:42:2:42:26 | functio ... rn x; } |
|
||||
| tst.js:46:2:46:9 | this.g() | tst.js:46:2:46:7 | this.g |
|
||||
| tst.js:53:3:53:10 | this.g() | tst.js:53:3:53:8 | this.g |
|
||||
| tst.js:56:17:56:29 | Math.random() | tst.js:56:17:56:27 | Math.random |
|
||||
| tst.js:60:15:60:21 | new A() | tst.js:60:19:60:19 | A |
|
||||
| tst.js:64:13:64:19 | new B() | tst.js:64:17:64:17 | B |
|
||||
| tst.js:66:5:66:9 | b.f() | tst.js:66:5:66:7 | b.f |
|
||||
| tst.js:69:1:69:10 | globalfn() | tst.js:69:1:69:8 | globalfn |
|
||||
| tst.js:70:1:70:11 | globalfn2() | tst.js:70:1:70:9 | globalfn2 |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode invk
|
||||
select invk, invk.getCalleeNode()
|
||||
@@ -0,0 +1,11 @@
|
||||
| classes.js:4:7:4:26 | console.log("Hello") | classes.js:4:19:4:25 | "Hello" |
|
||||
| classes.js:14:7:14:27 | console ... ello!") | classes.js:14:19:14:26 | "Hello!" |
|
||||
| es2015.js:3:5:3:21 | console.log("hi") | es2015.js:3:17:3:20 | "hi" |
|
||||
| es2015.js:27:5:27:23 | console.log(this.x) | es2015.js:27:17:27:22 | this.x |
|
||||
| n.js:1:9:1:22 | require('./m') | n.js:1:17:1:21 | './m' |
|
||||
| n.js:4:10:4:24 | require('./m2') | n.js:4:18:4:23 | './m2' |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:20:7:21 | 19 |
|
||||
| reflection.js:7:1:7:22 | reflective call | reflection.js:7:20:7:21 | 19 |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:17:8:24 | [23, 19] |
|
||||
| tst.js:22:1:22:4 | l(k) | tst.js:22:3:22:3 | k |
|
||||
| tst.js:42:2:42:29 | functio ... x; }(o) | tst.js:42:28:42:28 | o |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode invk
|
||||
select invk, invk.getLastArgument()
|
||||
@@ -0,0 +1,52 @@
|
||||
| a.js:2:1:2:5 | foo() | 0 |
|
||||
| a.js:3:1:3:5 | bar() | 0 |
|
||||
| a.js:4:1:4:5 | qux() | 0 |
|
||||
| a.js:7:1:7:5 | baz() | 0 |
|
||||
| classes.js:4:7:4:26 | console.log("Hello") | 1 |
|
||||
| classes.js:8:7:8:18 | this.hello() | 0 |
|
||||
| classes.js:14:7:14:27 | console ... ello!") | 1 |
|
||||
| classes.js:18:3:18:9 | new B() | 0 |
|
||||
| classes.js:18:3:18:17 | new B().hello() | 0 |
|
||||
| es2015.js:3:5:3:21 | console.log("hi") | 1 |
|
||||
| es2015.js:6:1:6:18 | new ExampleClass() | 0 |
|
||||
| es2015.js:10:5:10:22 | arguments.callee() | 0 |
|
||||
| es2015.js:16:5:16:11 | super() | 0 |
|
||||
| es2015.js:26:5:26:11 | super() | 0 |
|
||||
| es2015.js:27:5:27:23 | console.log(this.x) | 1 |
|
||||
| m.js:2:1:2:11 | exports.f() | 0 |
|
||||
| m.js:3:1:3:18 | module.exports.f() | 0 |
|
||||
| n.js:1:9:1:22 | require('./m') | 1 |
|
||||
| n.js:2:1:2:5 | m.f() | 0 |
|
||||
| n.js:4:10:4:24 | require('./m2') | 1 |
|
||||
| n.js:5:1:5:6 | m2.f() | 0 |
|
||||
| reflection.js:4:5:4:12 | sneaky() | 0 |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | 3 |
|
||||
| reflection.js:7:1:7:22 | reflective call | 2 |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | 2 |
|
||||
| tst.js:6:1:6:3 | f() | 0 |
|
||||
| tst.js:7:1:7:3 | g() | 0 |
|
||||
| tst.js:8:1:8:3 | h() | 0 |
|
||||
| tst.js:9:1:9:3 | k() | 0 |
|
||||
| tst.js:14:2:14:4 | m() | 0 |
|
||||
| tst.js:15:2:15:4 | l() | 0 |
|
||||
| tst.js:16:2:16:19 | arguments.callee() | 0 |
|
||||
| tst.js:17:2:17:4 | n() | 0 |
|
||||
| tst.js:18:2:18:4 | p() | 0 |
|
||||
| tst.js:19:2:19:4 | f() | 0 |
|
||||
| tst.js:22:1:22:4 | l(k) | 1 |
|
||||
| tst.js:24:1:24:7 | new f() | 0 |
|
||||
| tst.js:25:1:25:5 | new g | 0 |
|
||||
| tst.js:27:1:27:16 | (function(){})() | 0 |
|
||||
| tst.js:28:2:28:15 | function(){}() | 0 |
|
||||
| tst.js:33:4:33:11 | this.g() | 0 |
|
||||
| tst.js:41:1:41:5 | o.f() | 0 |
|
||||
| tst.js:42:1:42:34 | (functi ... o)).f() | 0 |
|
||||
| tst.js:42:2:42:29 | functio ... x; }(o) | 1 |
|
||||
| tst.js:46:2:46:9 | this.g() | 0 |
|
||||
| tst.js:53:3:53:10 | this.g() | 0 |
|
||||
| tst.js:56:17:56:29 | Math.random() | 0 |
|
||||
| tst.js:60:15:60:21 | new A() | 0 |
|
||||
| tst.js:64:13:64:19 | new B() | 0 |
|
||||
| tst.js:66:5:66:9 | b.f() | 0 |
|
||||
| tst.js:69:1:69:10 | globalfn() | 0 |
|
||||
| tst.js:70:1:70:11 | globalfn2() | 0 |
|
||||
@@ -0,0 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode invk
|
||||
select invk, invk.getNumArgument()
|
||||
@@ -0,0 +1 @@
|
||||
| tst.js:69:1:69:10 | globalfn() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode invk
|
||||
where invk.isImprecise()
|
||||
select invk
|
||||
@@ -0,0 +1,30 @@
|
||||
| a.js:7:1:7:5 | baz() |
|
||||
| classes.js:4:7:4:26 | console.log("Hello") |
|
||||
| classes.js:8:7:8:18 | this.hello() |
|
||||
| classes.js:14:7:14:27 | console ... ello!") |
|
||||
| classes.js:18:3:18:17 | new B().hello() |
|
||||
| es2015.js:3:5:3:21 | console.log("hi") |
|
||||
| es2015.js:27:5:27:23 | console.log(this.x) |
|
||||
| m.js:2:1:2:11 | exports.f() |
|
||||
| m.js:3:1:3:18 | module.exports.f() |
|
||||
| n.js:1:9:1:22 | require('./m') |
|
||||
| n.js:2:1:2:5 | m.f() |
|
||||
| n.js:4:10:4:24 | require('./m2') |
|
||||
| n.js:5:1:5:6 | m2.f() |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) |
|
||||
| tst.js:6:1:6:3 | f() |
|
||||
| tst.js:7:1:7:3 | g() |
|
||||
| tst.js:9:1:9:3 | k() |
|
||||
| tst.js:14:2:14:4 | m() |
|
||||
| tst.js:17:2:17:4 | n() |
|
||||
| tst.js:19:2:19:4 | f() |
|
||||
| tst.js:24:1:24:7 | new f() |
|
||||
| tst.js:25:1:25:5 | new g |
|
||||
| tst.js:33:4:33:11 | this.g() |
|
||||
| tst.js:41:1:41:5 | o.f() |
|
||||
| tst.js:42:1:42:34 | (functi ... o)).f() |
|
||||
| tst.js:46:2:46:9 | this.g() |
|
||||
| tst.js:53:3:53:10 | this.g() |
|
||||
| tst.js:56:17:56:29 | Math.random() |
|
||||
| tst.js:66:5:66:9 | b.f() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode invk
|
||||
where invk.isIncomplete()
|
||||
select invk
|
||||
@@ -0,0 +1,31 @@
|
||||
| a.js:7:1:7:5 | baz() |
|
||||
| classes.js:4:7:4:26 | console.log("Hello") |
|
||||
| classes.js:8:7:8:18 | this.hello() |
|
||||
| classes.js:14:7:14:27 | console ... ello!") |
|
||||
| classes.js:18:3:18:17 | new B().hello() |
|
||||
| es2015.js:3:5:3:21 | console.log("hi") |
|
||||
| es2015.js:27:5:27:23 | console.log(this.x) |
|
||||
| m.js:2:1:2:11 | exports.f() |
|
||||
| m.js:3:1:3:18 | module.exports.f() |
|
||||
| n.js:1:9:1:22 | require('./m') |
|
||||
| n.js:2:1:2:5 | m.f() |
|
||||
| n.js:4:10:4:24 | require('./m2') |
|
||||
| n.js:5:1:5:6 | m2.f() |
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) |
|
||||
| tst.js:6:1:6:3 | f() |
|
||||
| tst.js:7:1:7:3 | g() |
|
||||
| tst.js:9:1:9:3 | k() |
|
||||
| tst.js:14:2:14:4 | m() |
|
||||
| tst.js:17:2:17:4 | n() |
|
||||
| tst.js:19:2:19:4 | f() |
|
||||
| tst.js:24:1:24:7 | new f() |
|
||||
| tst.js:25:1:25:5 | new g |
|
||||
| tst.js:33:4:33:11 | this.g() |
|
||||
| tst.js:41:1:41:5 | o.f() |
|
||||
| tst.js:42:1:42:34 | (functi ... o)).f() |
|
||||
| tst.js:46:2:46:9 | this.g() |
|
||||
| tst.js:53:3:53:10 | this.g() |
|
||||
| tst.js:56:17:56:29 | Math.random() |
|
||||
| tst.js:66:5:66:9 | b.f() |
|
||||
| tst.js:69:1:69:10 | globalfn() |
|
||||
@@ -0,0 +1,5 @@
|
||||
import javascript
|
||||
|
||||
from DataFlow::InvokeNode invk
|
||||
where invk.isUncertain()
|
||||
select invk
|
||||
@@ -0,0 +1,8 @@
|
||||
function add(x, y) {
|
||||
return x+y;
|
||||
}
|
||||
if (sneaky())
|
||||
add.apply = function() { return 56; };
|
||||
|
||||
add.call(null, 23, 19);
|
||||
add.apply(null, [23, 19]);
|
||||
@@ -64,4 +64,7 @@ C.prototype.g = function() {};
|
||||
var b = new B();
|
||||
b.f = function() {};
|
||||
b.f();
|
||||
});
|
||||
});
|
||||
|
||||
globalfn();
|
||||
globalfn2();
|
||||
|
||||
1
javascript/ql/test/library-tests/CallGraphs/tst2.js
Normal file
1
javascript/ql/test/library-tests/CallGraphs/tst2.js
Normal file
@@ -0,0 +1 @@
|
||||
var globalfn = null;
|
||||
2
javascript/ql/test/library-tests/CallGraphs/tst3.js
Normal file
2
javascript/ql/test/library-tests/CallGraphs/tst3.js
Normal file
@@ -0,0 +1,2 @@
|
||||
function globalfn() {}
|
||||
function globalfn2() {}
|
||||
@@ -1,4 +1,4 @@
|
||||
import javascript
|
||||
|
||||
from CallSite call
|
||||
from DataFlow::InvokeNode call
|
||||
select call, call.getACallee()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import javascript
|
||||
|
||||
from NewExpr new, ClassDefinition klass
|
||||
where klass.getConstructor().getInit() = new.(CallSite).getACallee()
|
||||
from DataFlow::NewNode new, ClassDefinition klass
|
||||
where klass.getConstructor().getInit() = new.getACallee()
|
||||
select new.getFile().getBaseName(), new.getCalleeName(), klass.getFile().getBaseName(), klass.getName()
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
| tst.js:24:1:24:9 | new o.g() | Illegal invocation of $@ using 'new'. | tst.js:19:4:19:8 | () {} | a method |
|
||||
| tst.js:42:1:42:7 | new g() | Illegal invocation of $@ using 'new'. | tst.js:39:1:39:16 | function* g() {} | a generator function |
|
||||
| tst.js:43:1:43:7 | new h() | Illegal invocation of $@ using 'new'. | tst.js:40:1:40:21 | async f ... h() {} | an async function |
|
||||
| tst.js:45:1:45:8 | C.call() | Illegal invocation of $@ as a function. | tst.js:1:9:1:8 | () {} | a constructor |
|
||||
| tst.js:46:1:46:9 | C.apply() | Illegal invocation of $@ as a function. | tst.js:1:9:1:8 | () {} | a constructor |
|
||||
| tst.js:45:1:45:8 | reflective call | Illegal invocation of $@ as a function. | tst.js:1:9:1:8 | () {} | a constructor |
|
||||
| tst.js:46:1:46:9 | reflective call | Illegal invocation of $@ as a function. | tst.js:1:9:1:8 | () {} | a constructor |
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
| es2015.js:4:16:4:17 | 23 | Superfluous argument passed to $@. | es2015.js:2:14:2:32 | (x) { this.x = x; } | constructor of class Class1 |
|
||||
| es2015.js:17:11:17:12 | 42 | Superfluous argument passed to $@. | es2015.js:15:13:15:12 | () {} | default constructor of class Other |
|
||||
| es2015.js:21:3:21:13 | 42 | Superfluous arguments passed to $@. | tst.js:1:1:4:1 | functio ... x+19;\\n} | function f |
|
||||
| es2015.js:21:3:21:4 | 42 | Superfluous argument passed to $@. | tst.js:1:1:4:1 | functio ... x+19;\\n} | function f |
|
||||
| globals.js:15:13:15:13 | x | Superfluous argument passed to $@. | globals.js:9:1:9:25 | functio ... al() {} | function otherglobal |
|
||||
| globals.js:16:24:16:24 | x | Superfluous argument passed to $@. | globals.js:9:1:9:25 | functio ... al() {} | function otherglobal |
|
||||
| globals.js:17:24:17:27 | x | Superfluous arguments passed to $@. | globals.js:9:1:9:25 | functio ... al() {} | function otherglobal |
|
||||
| reflection.js:6:15:6:15 | 1 | Superfluous argument passed to $@. | reflection.js:1:1:1:16 | function f0() {} | function f0 |
|
||||
| reflection.js:7:15:7:18 | 1 | Superfluous arguments passed to $@. | reflection.js:1:1:1:16 | function f0() {} | function f0 |
|
||||
| reflection.js:12:18:12:18 | 2 | Superfluous argument passed to $@. | reflection.js:2:1:2:17 | function f1(x) {} | function f1 |
|
||||
| thisparameter.ts:4:11:4:12 | 45 | Superfluous argument passed to $@. | thisparameter.ts:1:1:1:38 | functio ... ber) {} | function foo |
|
||||
| tst.js:11:3:11:5 | g() | Superfluous argument passed to $@. | tst.js:1:1:4:1 | functio ... x+19;\\n} | function f |
|
||||
| tst.js:33:15:33:18 | 2 | Superfluous arguments passed to $@. | externs.js:34:1:34:27 | functio ... str) {} | function String |
|
||||
|
||||
@@ -12,4 +12,6 @@ var o = {
|
||||
otherglobal: function (x) {}
|
||||
};
|
||||
|
||||
otherglobal(x); // NOT OK: can never refer to function on line 12
|
||||
otherglobal(x); // NOT OK: can never refer to function on line 12
|
||||
otherglobal.call(null, x); // NOT OK
|
||||
otherglobal.call(null, x, y); // NOT OK
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
function f0() {}
|
||||
function f1(x) {}
|
||||
|
||||
f0.call();
|
||||
f0.call(this);
|
||||
f0.call(this, 1);
|
||||
f0.call(this, 1, 2);
|
||||
|
||||
f1.call();
|
||||
f1.call(this);
|
||||
f1.call(this, 1);
|
||||
f1.call(this, 1, 2);
|
||||
|
||||
f0.apply();
|
||||
f0.apply(this);
|
||||
f0.apply(this, []);
|
||||
f0.apply(this, [1]);
|
||||
f0.apply(this, [1, 2]);
|
||||
|
||||
f1.apply();
|
||||
f1.apply(this);
|
||||
f1.apply(this, []);
|
||||
f1.apply(this, [1]);
|
||||
f1.apply(this, [1, 2]);
|
||||
@@ -1,6 +1,6 @@
|
||||
import javascript
|
||||
|
||||
from CallSite cs
|
||||
from DataFlow::InvokeNode cs
|
||||
where not cs.isIncomplete() and
|
||||
not exists(cs.getACallee())
|
||||
select cs, "Unable to find a callee for this call site."
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
function f0() {}
|
||||
function f1(x) {}
|
||||
|
||||
f0.call();
|
||||
f0.call(this);
|
||||
f0.call(this, 1);
|
||||
f0.call(this, 1, 2);
|
||||
|
||||
f1.call();
|
||||
f1.call(this);
|
||||
f1.call(this, 1);
|
||||
f1.call(this, 1, 2);
|
||||
|
||||
f0.apply();
|
||||
f0.apply(this);
|
||||
f0.apply(this, []);
|
||||
f0.apply(this, [1]);
|
||||
f0.apply(this, [1, 2]);
|
||||
|
||||
f1.apply();
|
||||
f1.apply(this);
|
||||
f1.apply(this, []);
|
||||
f1.apply(this, [1]);
|
||||
f1.apply(this, [1, 2]);
|
||||
Reference in New Issue
Block a user