mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge branch 'main' into atorralba/promote-ognl-injection
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Increase coverage of dataflow through Jackson JSON deserialized objects.
|
||||
3
java/change-notes/2021-05-05-kryo-improvements.md
Normal file
3
java/change-notes/2021-05-05-kryo-improvements.md
Normal file
@@ -0,0 +1,3 @@
|
||||
lgtm,codescanning
|
||||
* Add support for version 5 of the Kryo serialization/deserialization framework.
|
||||
* Add support for detecting safe uses of Kryo utilizing `KryoPool.Builder`. [#4992](https://github.com/github/codeql/issues/4992)
|
||||
2
java/change-notes/2021-05-12-xxe-fp-fix.md
Normal file
2
java/change-notes/2021-05-12-xxe-fp-fix.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The query "Resolving XML external entity in user-controlled data" (`java/xxe`) has been improved to report fewer false positives when a Builder / Factory (e.g. an `XMLInputFactory`) is configured safely by using a boxed boolean as second argument to one or more of its configuration methods.
|
||||
@@ -6,6 +6,7 @@
|
||||
* or comments.
|
||||
* @kind metric
|
||||
* @tags summary
|
||||
* lines-of-code
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import org.python.util.PythonInterpreter;
|
||||
|
||||
public class JythonInjection extends HttpServlet {
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
String code = request.getParameter("code");
|
||||
PythonInterpreter interpreter = null;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
interpreter = new PythonInterpreter();
|
||||
interpreter.setOut(out);
|
||||
interpreter.setErr(out);
|
||||
|
||||
// BAD: allow execution of arbitrary Python code
|
||||
interpreter.exec(code);
|
||||
out.flush();
|
||||
|
||||
response.getWriter().print(out.toString());
|
||||
} catch(PyException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
if (interpreter != null) {
|
||||
interpreter.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
String code = request.getParameter("code");
|
||||
PythonInterpreter interpreter = null;
|
||||
|
||||
try {
|
||||
interpreter = new PythonInterpreter();
|
||||
// BAD: allow execution of arbitrary Python code
|
||||
PyObject py = interpreter.eval(code);
|
||||
|
||||
response.getWriter().print(py.toString());
|
||||
} catch(PyException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
if (interpreter != null) {
|
||||
interpreter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>Python has been the most widely used programming language in recent years, and Jython
|
||||
(formerly known as JPython) is a popular Java implementation of Python. It allows
|
||||
embedded Python scripting inside Java applications and provides an interactive interpreter
|
||||
that can be used to interact with Java packages or with running Java applications. If an
|
||||
expression is built using attacker-controlled data and then evaluated, it may allow the
|
||||
attacker to run arbitrary code.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>In general, including user input in Jython expression should be avoided. If user input
|
||||
must be included in an expression, it should be then evaluated in a safe context that
|
||||
doesn't allow arbitrary code invocation.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>The following code could execute arbitrary code in Jython Interpreter</p>
|
||||
<sample src="JythonInjection.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
Jython Organization: <a href="https://jython.readthedocs.io/en/latest/JythonAndJavaIntegration/">Jython and Java Integration</a>
|
||||
</li>
|
||||
<li>
|
||||
PortSwigger: <a href="https://portswigger.net/kb/issues/00100f10_python-code-injection">Python code injection</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
112
java/ql/src/experimental/Security/CWE/CWE-094/JythonInjection.ql
Normal file
112
java/ql/src/experimental/Security/CWE/CWE-094/JythonInjection.ql
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* @name Injection in Jython
|
||||
* @description Evaluation of a user-controlled malicious expression in Java Python
|
||||
* interpreter may lead to remote code execution.
|
||||
* @kind path-problem
|
||||
* @id java/jython-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-094
|
||||
* external/cwe/cwe-095
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.frameworks.spring.SpringController
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/** The class `org.python.util.PythonInterpreter`. */
|
||||
class PythonInterpreter extends RefType {
|
||||
PythonInterpreter() { this.hasQualifiedName("org.python.util", "PythonInterpreter") }
|
||||
}
|
||||
|
||||
/** A method that evaluates, compiles or executes a Jython expression. */
|
||||
class InterpretExprMethod extends Method {
|
||||
InterpretExprMethod() {
|
||||
this.getDeclaringType().getAnAncestor*() instanceof PythonInterpreter and
|
||||
getName().matches(["exec%", "run%", "eval", "compile"])
|
||||
}
|
||||
}
|
||||
|
||||
/** The class `org.python.core.BytecodeLoader`. */
|
||||
class BytecodeLoader extends RefType {
|
||||
BytecodeLoader() { this.hasQualifiedName("org.python.core", "BytecodeLoader") }
|
||||
}
|
||||
|
||||
/** Holds if a Jython expression if evaluated, compiled or executed. */
|
||||
predicate runsCode(MethodAccess ma, Expr sink) {
|
||||
exists(Method m | m = ma.getMethod() |
|
||||
m instanceof InterpretExprMethod and
|
||||
sink = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
/** A method that loads Java class data. */
|
||||
class LoadClassMethod extends Method {
|
||||
LoadClassMethod() {
|
||||
this.getDeclaringType().getAnAncestor*() instanceof BytecodeLoader and
|
||||
hasName(["makeClass", "makeCode"])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` is a call to a class-loading method, and `sink` is the byte array
|
||||
* representing the class to be loaded.
|
||||
*/
|
||||
predicate loadsClass(MethodAccess ma, Expr sink) {
|
||||
exists(Method m, int i | m = ma.getMethod() |
|
||||
m instanceof LoadClassMethod and
|
||||
m.getParameter(i).getType() instanceof Array and // makeClass(java.lang.String name, byte[] data, ...)
|
||||
sink = ma.getArgument(i)
|
||||
)
|
||||
}
|
||||
|
||||
/** The class `org.python.core.Py`. */
|
||||
class Py extends RefType {
|
||||
Py() { this.hasQualifiedName("org.python.core", "Py") }
|
||||
}
|
||||
|
||||
/** A method declared on class `Py` or one of its descendants that compiles Python code. */
|
||||
class PyCompileMethod extends Method {
|
||||
PyCompileMethod() {
|
||||
this.getDeclaringType().getAnAncestor*() instanceof Py and
|
||||
getName().matches("compile%")
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if source code is compiled with `PyCompileMethod`. */
|
||||
predicate compile(MethodAccess ma, Expr sink) {
|
||||
exists(Method m | m = ma.getMethod() |
|
||||
m instanceof PyCompileMethod and
|
||||
sink = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
/** An expression loaded by Jython. */
|
||||
class CodeInjectionSink extends DataFlow::ExprNode {
|
||||
MethodAccess methodAccess;
|
||||
|
||||
CodeInjectionSink() {
|
||||
runsCode(methodAccess, this.getExpr()) or
|
||||
loadsClass(methodAccess, this.getExpr()) or
|
||||
compile(methodAccess, this.getExpr())
|
||||
}
|
||||
|
||||
MethodAccess getMethodAccess() { result = methodAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint configuration for tracking flow from `RemoteFlowSource` to a Jython method call
|
||||
* `CodeInjectionSink` that executes injected code.
|
||||
*/
|
||||
class CodeInjectionConfiguration extends TaintTracking::Configuration {
|
||||
CodeInjectionConfiguration() { this = "CodeInjectionConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof CodeInjectionSink }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, CodeInjectionConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode().(CodeInjectionSink).getMethodAccess(), source, sink, "Jython evaluate $@.",
|
||||
source.getNode(), "user input"
|
||||
@@ -0,0 +1,40 @@
|
||||
import org.mozilla.javascript.ClassShutter;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
public class RhinoInjection extends HttpServlet {
|
||||
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
String code = request.getParameter("code");
|
||||
Context ctx = Context.enter();
|
||||
try {
|
||||
{
|
||||
// BAD: allow arbitrary Java and JavaScript code to be executed
|
||||
Scriptable scope = ctx.initStandardObjects();
|
||||
}
|
||||
|
||||
{
|
||||
// GOOD: enable the safe mode
|
||||
Scriptable scope = ctx.initSafeStandardObjects();
|
||||
}
|
||||
|
||||
{
|
||||
// GOOD: enforce a constraint on allowed classes
|
||||
Scriptable scope = ctx.initStandardObjects();
|
||||
ctx.setClassShutter(new ClassShutter() {
|
||||
public boolean visibleToScripts(String className) {
|
||||
return className.startsWith("com.example.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Object result = ctx.evaluateString(scope, code, "<code>", 1, null);
|
||||
response.getWriter().print(Context.toString(result));
|
||||
} catch(RhinoException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
Context.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>The ScriptEngine API has been available since the release of Java 6.
|
||||
It allows applications to interact with scripts written in languages such as JavaScript.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Use "Cloudbees Rhino Sandbox" or sandboxing with SecurityManager or use <a href="https://www.graalvm.org/">graalvm</a> instead.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>The following code could execute random JavaScript code</p>
|
||||
<sample src="ScriptEngine.java" />
|
||||
<sample src="NashornScriptEngine.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
CERT coding standard: <a href="https://wiki.sei.cmu.edu/confluence/display/java/IDS52-J.+Prevent+code+injection">ScriptEngine code injection</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* @name ScriptEngine evaluation
|
||||
* @description Malicious Javascript code could cause arbitrary command execution at the OS level
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/unsafe-eval
|
||||
* @tags security
|
||||
* external/cwe/cwe-094
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class ScriptEngineMethod extends Method {
|
||||
ScriptEngineMethod() {
|
||||
this.getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "ScriptEngine") and
|
||||
this.hasName("eval")
|
||||
}
|
||||
}
|
||||
|
||||
predicate scriptEngine(MethodAccess ma, Expr sink) {
|
||||
exists(Method m | m = ma.getMethod() |
|
||||
m instanceof ScriptEngineMethod and
|
||||
sink = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
class ScriptEngineSink extends DataFlow::ExprNode {
|
||||
ScriptEngineSink() { scriptEngine(_, this.getExpr()) }
|
||||
|
||||
MethodAccess getMethodAccess() { scriptEngine(result, this.getExpr()) }
|
||||
}
|
||||
|
||||
class ScriptEngineConfiguration extends TaintTracking::Configuration {
|
||||
ScriptEngineConfiguration() { this = "ScriptEngineConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source instanceof RemoteFlowSource
|
||||
or
|
||||
source instanceof LocalUserInput
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ScriptEngineSink }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ScriptEngineConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode().(ScriptEngineSink).getMethodAccess(), source, sink, "ScriptEngine eval $@.",
|
||||
source.getNode(), "user input"
|
||||
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>The Java Scripting API has been available since the release of Java 6. It allows
|
||||
applications to interact with scripts written in languages such as JavaScript. It serves
|
||||
as an embedded scripting engine inside Java applications which allows Java-to-JavaScript
|
||||
interoperability and provides a seamless integration between the two languages. If an
|
||||
expression is built using attacker-controlled data, and then evaluated in a powerful
|
||||
context, it may allow the attacker to run arbitrary code.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>In general, including user input in a Java Script Engine expression should be avoided.
|
||||
If user input must be included in the expression, it should be then evaluated in a safe
|
||||
context that doesn't allow arbitrary code invocation. Use "Cloudbees Rhino Sandbox" or
|
||||
sandboxing with SecurityManager, which will be deprecated in a future release, or use
|
||||
<a href="https://www.graalvm.org/">GraalVM</a> instead.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>The following code could execute user-supplied JavaScript code in <code>ScriptEngine</code></p>
|
||||
<sample src="ScriptEngine.java" />
|
||||
<sample src="NashornScriptEngine.java" />
|
||||
|
||||
<p>The following example shows two ways of using Rhino expression. In the 'BAD' case,
|
||||
an unsafe context is initialized with <code>initStandardObjects</code> that allows arbitrary
|
||||
Java code to be executed. In the 'GOOD' case, a safe context is initialized with
|
||||
<code>initSafeStandardObjects</code> or <code>setClassShutter</code>.</p>
|
||||
<sample src="RhinoInjection.java" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
CERT coding standard: <a href="https://wiki.sei.cmu.edu/confluence/display/java/IDS52-J.+Prevent+code+injection">ScriptEngine code injection</a>
|
||||
</li>
|
||||
<li>
|
||||
GraalVM: <a href="https://www.graalvm.org/reference-manual/js/NashornMigrationGuide/#secure-by-default">Secure by Default</a>
|
||||
</li>
|
||||
<li>
|
||||
Mozilla Rhino: <a href="https://github.com/mozilla/rhino">Rhino: JavaScript in Java</a>
|
||||
</li>
|
||||
<li>
|
||||
Rhino Sandbox: <a href="https://github.com/javadelight/delight-rhino-sandbox">A sandbox to execute JavaScript code with Rhino in Java</a>
|
||||
</li>
|
||||
<li>
|
||||
GuardRails: <a href="https://docs.guardrails.io/docs/en/vulnerabilities/java/insecure_use_of_dangerous_function#code-injection">Code Injection</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
146
java/ql/src/experimental/Security/CWE/CWE-094/ScriptInjection.ql
Normal file
146
java/ql/src/experimental/Security/CWE/CWE-094/ScriptInjection.ql
Normal file
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* @name Injection in Java Script Engine
|
||||
* @description Evaluation of user-controlled data using the Java Script Engine may
|
||||
* lead to remote code execution.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/unsafe-eval
|
||||
* @tags security
|
||||
* external/cwe/cwe-094
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/** A method of ScriptEngine that allows code injection. */
|
||||
class ScriptEngineMethod extends Method {
|
||||
ScriptEngineMethod() {
|
||||
this.getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "ScriptEngine") and
|
||||
this.hasName("eval")
|
||||
or
|
||||
this.getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "Compilable") and
|
||||
this.hasName("compile")
|
||||
or
|
||||
this.getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "ScriptEngineFactory") and
|
||||
this.hasName(["getProgram", "getMethodCallSyntax"])
|
||||
}
|
||||
}
|
||||
|
||||
/** The context class `org.mozilla.javascript.Context` of Rhino Java Script Engine. */
|
||||
class RhinoContext extends RefType {
|
||||
RhinoContext() { this.hasQualifiedName("org.mozilla.javascript", "Context") }
|
||||
}
|
||||
|
||||
/** A method that evaluates a Rhino expression with `org.mozilla.javascript.Context`. */
|
||||
class RhinoEvaluateExpressionMethod extends Method {
|
||||
RhinoEvaluateExpressionMethod() {
|
||||
this.getDeclaringType().getAnAncestor*() instanceof RhinoContext and
|
||||
this.hasName([
|
||||
"evaluateString", "evaluateReader", "compileFunction", "compileReader", "compileString"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that compiles a Rhino expression with
|
||||
* `org.mozilla.javascript.optimizer.ClassCompiler`.
|
||||
*/
|
||||
class RhinoCompileClassMethod extends Method {
|
||||
RhinoCompileClassMethod() {
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.hasQualifiedName("org.mozilla.javascript.optimizer", "ClassCompiler") and
|
||||
this.hasName("compileToClassFiles")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that defines a Java class from a Rhino expression with
|
||||
* `org.mozilla.javascript.GeneratedClassLoader`.
|
||||
*/
|
||||
class RhinoDefineClassMethod extends Method {
|
||||
RhinoDefineClassMethod() {
|
||||
this.getDeclaringType()
|
||||
.getASupertype*()
|
||||
.hasQualifiedName("org.mozilla.javascript", "GeneratedClassLoader") and
|
||||
this.hasName("defineClass")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ma` is a call to a `ScriptEngineMethod` and `sink` is an argument that
|
||||
* will be executed.
|
||||
*/
|
||||
predicate isScriptArgument(MethodAccess ma, Expr sink) {
|
||||
exists(ScriptEngineMethod m |
|
||||
m = ma.getMethod() and
|
||||
if m.getDeclaringType().getASupertype*().hasQualifiedName("javax.script", "ScriptEngineFactory")
|
||||
then sink = ma.getArgument(_) // all arguments allow script injection
|
||||
else sink = ma.getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a Rhino expression evaluation method is vulnerable to code injection.
|
||||
*/
|
||||
predicate evaluatesRhinoExpression(MethodAccess ma, Expr sink) {
|
||||
exists(RhinoEvaluateExpressionMethod m | m = ma.getMethod() |
|
||||
(
|
||||
if ma.getMethod().getName() = "compileReader"
|
||||
then sink = ma.getArgument(0) // The first argument is the input reader
|
||||
else sink = ma.getArgument(1) // The second argument is the JavaScript or Java input
|
||||
) and
|
||||
not exists(MethodAccess ca |
|
||||
ca.getMethod().hasName(["initSafeStandardObjects", "setClassShutter"]) and // safe mode or `ClassShutter` constraint is enforced
|
||||
ma.getQualifier() = ca.getQualifier().(VarAccess).getVariable().getAnAccess()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a Rhino expression compilation method is vulnerable to code injection.
|
||||
*/
|
||||
predicate compilesScript(MethodAccess ma, Expr sink) {
|
||||
exists(RhinoCompileClassMethod m | m = ma.getMethod() | sink = ma.getArgument(0))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a Rhino class loading method is vulnerable to code injection.
|
||||
*/
|
||||
predicate definesRhinoClass(MethodAccess ma, Expr sink) {
|
||||
exists(RhinoDefineClassMethod m | m = ma.getMethod() | sink = ma.getArgument(1))
|
||||
}
|
||||
|
||||
/** A script injection sink. */
|
||||
class ScriptInjectionSink extends DataFlow::ExprNode {
|
||||
MethodAccess methodAccess;
|
||||
|
||||
ScriptInjectionSink() {
|
||||
isScriptArgument(methodAccess, this.getExpr()) or
|
||||
evaluatesRhinoExpression(methodAccess, this.getExpr()) or
|
||||
compilesScript(methodAccess, this.getExpr()) or
|
||||
definesRhinoClass(methodAccess, this.getExpr())
|
||||
}
|
||||
|
||||
/** An access to the method associated with this sink. */
|
||||
MethodAccess getMethodAccess() { result = methodAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint tracking configuration that tracks flow from `RemoteFlowSource` to an argument
|
||||
* of a method call that executes injected script.
|
||||
*/
|
||||
class ScriptInjectionConfiguration extends TaintTracking::Configuration {
|
||||
ScriptInjectionConfiguration() { this = "ScriptInjectionConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ScriptInjectionSink }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ScriptInjectionConfiguration conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode().(ScriptInjectionSink).getMethodAccess(), source, sink,
|
||||
"Java Script Engine evaluate $@.", source.getNode(), "user input"
|
||||
@@ -0,0 +1,46 @@
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
@Controller
|
||||
public class SpringUrlRedirect {
|
||||
|
||||
private final static String VALID_REDIRECT = "http://127.0.0.1";
|
||||
|
||||
@GetMapping("url1")
|
||||
public RedirectView bad1(String redirectUrl, HttpServletResponse response) throws Exception {
|
||||
RedirectView rv = new RedirectView();
|
||||
rv.setUrl(redirectUrl);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@GetMapping("url2")
|
||||
public String bad2(String redirectUrl) {
|
||||
String url = "redirect:" + redirectUrl;
|
||||
return url;
|
||||
}
|
||||
|
||||
@GetMapping("url3")
|
||||
public RedirectView bad3(String redirectUrl) {
|
||||
RedirectView rv = new RedirectView(redirectUrl);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@GetMapping("url4")
|
||||
public ModelAndView bad4(String redirectUrl) {
|
||||
return new ModelAndView("redirect:" + redirectUrl);
|
||||
}
|
||||
|
||||
@GetMapping("url5")
|
||||
public RedirectView good1(String redirectUrl) {
|
||||
RedirectView rv = new RedirectView();
|
||||
if (redirectUrl.startsWith(VALID_REDIRECT)){
|
||||
rv.setUrl(redirectUrl);
|
||||
}else {
|
||||
rv.setUrl(VALID_REDIRECT);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>Directly incorporating user input into a URL redirect request without validating the input
|
||||
can facilitate phishing attacks. In these attacks, unsuspecting users can be redirected to a
|
||||
malicious site that looks very similar to the real site they intend to visit, but which is
|
||||
controlled by the attacker.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>To guard against untrusted URL redirection, it is advisable to avoid putting user input
|
||||
directly into a redirect URL. Instead, maintain a list of authorized
|
||||
redirects on the server; then choose from that list based on the user input provided.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>The following examples show the bad case and the good case respectively.
|
||||
In <code>bad1</code> method and <code>bad2</code> method and <code>bad3</code> method and
|
||||
<code>bad4</code> method, shows an HTTP request parameter being used directly in a URL redirect
|
||||
without validating the input, which facilitates phishing attacks. In <code>good1</code> method,
|
||||
shows how to solve this problem by verifying whether the user input is a known fixed string beginning.
|
||||
</p>
|
||||
|
||||
<sample src="SpringUrlRedirect.java" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
<li>A Guide To Spring Redirects: <a href="https://www.baeldung.com/spring-redirect-and-forward">Spring Redirects</a>.</li>
|
||||
<li>Url redirection - attack and defense: <a href="https://www.virtuesecurity.com/kb/url-redirection-attack-and-defense/">Url Redirection</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @name Spring url redirection from remote source
|
||||
* @description Spring url redirection based on unvalidated user-input
|
||||
* may cause redirection to malicious web sites.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/spring-unvalidated-url-redirection
|
||||
* @tags security
|
||||
* external/cwe-601
|
||||
*/
|
||||
|
||||
import java
|
||||
import SpringUrlRedirect
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
|
||||
private class StartsWithSanitizer extends DataFlow::BarrierGuard {
|
||||
StartsWithSanitizer() {
|
||||
this.(MethodAccess).getMethod().hasName("startsWith") and
|
||||
this.(MethodAccess).getMethod().getDeclaringType() instanceof TypeString and
|
||||
this.(MethodAccess).getMethod().getNumberOfParameters() = 1
|
||||
}
|
||||
|
||||
override predicate checks(Expr e, boolean branch) {
|
||||
e = this.(MethodAccess).getQualifier() and branch = true
|
||||
}
|
||||
}
|
||||
|
||||
class SpringUrlRedirectFlowConfig extends TaintTracking::Configuration {
|
||||
SpringUrlRedirectFlowConfig() { this = "SpringUrlRedirectFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof SpringUrlRedirectSink }
|
||||
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof StartsWithSanitizer
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
// Exclude the case where the left side of the concatenated string is not `redirect:`.
|
||||
// E.g: `String url = "/path?token=" + request.getParameter("token");`
|
||||
// Note this is quite a broad sanitizer (it will also sanitize the right-hand side of `url = "http://" + request.getParameter("token")`);
|
||||
// Consider making this stricter in future.
|
||||
exists(AddExpr ae |
|
||||
ae.getRightOperand() = node.asExpr() and
|
||||
not ae instanceof RedirectBuilderExpr
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma, int index |
|
||||
ma.getMethod().hasName("format") and
|
||||
ma.getMethod().getDeclaringType() instanceof TypeString and
|
||||
ma.getArgument(index) = node.asExpr() and
|
||||
(
|
||||
index != 0 and
|
||||
not ma.getArgument(0).(CompileTimeConstantExpr).getStringValue().regexpMatch("^%s.*")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, SpringUrlRedirectFlowConfig conf
|
||||
where conf.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Potentially untrusted URL redirection due to $@.",
|
||||
source.getNode(), "user-provided value"
|
||||
@@ -0,0 +1,73 @@
|
||||
import java
|
||||
import DataFlow
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import semmle.code.java.dataflow.DataFlow2
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.frameworks.spring.SpringController
|
||||
|
||||
/**
|
||||
* A concatenate expression using the string `redirect:` or `ajaxredirect:` or `forward:` on the left.
|
||||
*
|
||||
* E.g: `"redirect:" + redirectUrl`
|
||||
*/
|
||||
class RedirectBuilderExpr extends AddExpr {
|
||||
RedirectBuilderExpr() {
|
||||
this.getLeftOperand().(CompileTimeConstantExpr).getStringValue() in [
|
||||
"redirect:", "ajaxredirect:", "forward:"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `StringBuilder.append` or `StringBuffer.append` method, and the parameter value is
|
||||
* `"redirect:"` or `"ajaxredirect:"` or `"forward:"`.
|
||||
*
|
||||
* E.g: `StringBuilder.append("redirect:")`
|
||||
*/
|
||||
class RedirectAppendCall extends MethodAccess {
|
||||
RedirectAppendCall() {
|
||||
this.getMethod().hasName("append") and
|
||||
this.getMethod().getDeclaringType() instanceof StringBuildingType and
|
||||
this.getArgument(0).(CompileTimeConstantExpr).getStringValue() in [
|
||||
"redirect:", "ajaxredirect:", "forward:"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/** A URL redirection sink from spring controller method. */
|
||||
class SpringUrlRedirectSink extends DataFlow::Node {
|
||||
SpringUrlRedirectSink() {
|
||||
exists(RedirectBuilderExpr rbe |
|
||||
rbe.getRightOperand() = this.asExpr() and
|
||||
any(SpringRequestMappingMethod sqmm).polyCalls*(this.getEnclosingCallable())
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma, RedirectAppendCall rac |
|
||||
DataFlow2::localExprFlow(rac.getQualifier(), ma.getQualifier()) and
|
||||
ma.getMethod().hasName("append") and
|
||||
ma.getArgument(0) = this.asExpr() and
|
||||
any(SpringRequestMappingMethod sqmm).polyCalls*(this.getEnclosingCallable())
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod().hasName("setUrl") and
|
||||
ma.getMethod()
|
||||
.getDeclaringType()
|
||||
.hasQualifiedName("org.springframework.web.servlet.view", "AbstractUrlBasedView") and
|
||||
ma.getArgument(0) = this.asExpr()
|
||||
)
|
||||
or
|
||||
exists(ClassInstanceExpr cie |
|
||||
cie.getConstructedType()
|
||||
.hasQualifiedName("org.springframework.web.servlet.view", "RedirectView") and
|
||||
cie.getArgument(0) = this.asExpr()
|
||||
)
|
||||
or
|
||||
exists(ClassInstanceExpr cie |
|
||||
cie.getConstructedType().hasQualifiedName("org.springframework.web.servlet", "ModelAndView") and
|
||||
exists(RedirectBuilderExpr rbe |
|
||||
rbe = cie.getArgument(0) and rbe.getRightOperand() = this.asExpr()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -77,6 +77,7 @@ private module Frameworks {
|
||||
private import semmle.code.java.frameworks.ApacheHttp
|
||||
private import semmle.code.java.frameworks.apache.Lang
|
||||
private import semmle.code.java.frameworks.guava.Guava
|
||||
private import semmle.code.java.frameworks.jackson.JacksonSerializability
|
||||
private import semmle.code.java.security.ResponseSplitting
|
||||
private import semmle.code.java.security.XSS
|
||||
private import semmle.code.java.security.LdapInjection
|
||||
@@ -293,6 +294,7 @@ private predicate summaryModelCsv(string row) {
|
||||
"java.util;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint",
|
||||
"java.beans;XMLDecoder;false;XMLDecoder;;;Argument[0];Argument[-1];taint",
|
||||
"com.esotericsoftware.kryo.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
|
||||
"com.esotericsoftware.kryo5.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;BufferedInputStream;false;BufferedInputStream;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;DataInputStream;false;DataInputStream;;;Argument[0];Argument[-1];taint",
|
||||
"java.io;ByteArrayInputStream;false;ByteArrayInputStream;;;Argument[0];Argument[-1];taint",
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2155,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2300,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2348,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2489,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2502,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2555,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3235,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3248,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3568,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3591,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3611,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3625,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3783,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3797,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3813,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3827,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3924,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3943,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3980,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4037,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4115,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4138,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2155,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2300,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2348,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2489,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2502,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2555,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3235,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3248,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3568,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3591,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3611,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3625,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3783,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3797,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3813,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3827,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3924,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3943,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3980,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4037,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4115,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4138,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2155,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2300,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2348,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2489,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2502,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2555,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3235,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3248,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3568,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3591,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3611,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3625,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3783,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3797,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3813,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3827,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3924,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3943,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3980,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4037,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4115,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4138,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2155,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2300,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2348,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2489,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2502,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2555,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3235,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3248,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3568,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3591,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3611,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3625,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3783,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3797,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3813,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3827,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3924,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3943,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3980,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4037,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4115,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4138,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2155,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2300,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2348,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2489,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2502,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2555,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3235,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3248,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3568,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3591,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3611,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3625,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3783,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3797,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3813,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3827,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3924,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3943,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3980,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4037,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4115,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4138,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2155,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2300,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2348,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2489,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2502,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2555,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3235,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3248,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3568,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3591,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3611,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3625,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3783,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3797,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3813,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3827,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3924,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3943,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3980,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4037,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4115,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4138,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -35,22 +35,22 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||
*/
|
||||
private module LambdaFlow {
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
@@ -118,8 +118,8 @@ private module LambdaFlow {
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
|
||||
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeType(node))
|
||||
if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeDataFlowType(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ private module LambdaFlow {
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
lambdaCall(lambdaCall, kind, node) and
|
||||
t = getNodeType(node) and
|
||||
t = getNodeDataFlowType(node) and
|
||||
toReturn = false and
|
||||
toJump = false and
|
||||
lastCall = TDataFlowCallNone()
|
||||
@@ -146,7 +146,7 @@ private module LambdaFlow {
|
||||
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
t = getNodeDataFlowType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
@@ -160,7 +160,7 @@ private module LambdaFlow {
|
||||
toJump = true and
|
||||
lastCall = TDataFlowCallNone()
|
||||
|
|
||||
jumpStep(node, mid) and
|
||||
jumpStepCached(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
@@ -168,7 +168,7 @@ private module LambdaFlow {
|
||||
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
t = getNodeDataFlowType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
@@ -176,7 +176,7 @@ private module LambdaFlow {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
|
||||
(
|
||||
if lastCall0 = TDataFlowCallNone() and toJump = false
|
||||
@@ -227,7 +227,7 @@ private module LambdaFlow {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowIn(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
|
||||
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
|
||||
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
|
||||
* collapsing the two stages.
|
||||
*/
|
||||
cached
|
||||
predicate forceCachingInSameStage() { any() }
|
||||
|
||||
cached
|
||||
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
|
||||
|
||||
cached
|
||||
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
|
||||
c = call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
cached
|
||||
predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
|
||||
|
||||
cached
|
||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||
|
||||
cached
|
||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||
|
||||
cached
|
||||
predicate outNodeExt(Node n) {
|
||||
n instanceof OutNode
|
||||
or
|
||||
n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hiddenNode(Node n) { nodeIsHidden(n) }
|
||||
|
||||
cached
|
||||
OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
|
||||
result = getAnOutNode(call, k.(ValueReturnKind).getKind())
|
||||
or
|
||||
exists(ArgNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||
k = TValueReturn(n.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParamNode p, int pos |
|
||||
parameterValueFlowsToPreUpdate(p, n) and
|
||||
p.isParameterOf(_, pos) and
|
||||
k = TParamUpdate(pos)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate castNode(Node n) { n instanceof CastNode }
|
||||
|
||||
cached
|
||||
predicate castingNode(Node n) {
|
||||
castNode(n) or
|
||||
n instanceof ParamNode or
|
||||
n instanceof OutNodeExt or
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
read(_, _, n)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate parameterNode(Node n, DataFlowCallable c, int i) {
|
||||
n.(ParameterNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
||||
n.(ArgumentNode).argumentOf(call, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable target for the lambda call `call`.
|
||||
*
|
||||
@@ -261,7 +344,7 @@ private module Cached {
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
|
||||
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
@@ -270,11 +353,11 @@ private module Cached {
|
||||
* dispatch into account.
|
||||
*/
|
||||
cached
|
||||
predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParam(call, i, p) and
|
||||
arg.argumentOf(call, i) and
|
||||
compatibleTypes(getNodeType(arg), getNodeType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -312,7 +395,7 @@ private module Cached {
|
||||
* `read` indicates whether it is contents of `p` that can flow to `node`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) {
|
||||
private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
|
||||
p = node and
|
||||
read = false
|
||||
or
|
||||
@@ -325,30 +408,30 @@ private module Cached {
|
||||
// read
|
||||
exists(Node mid |
|
||||
parameterValueFlowCand(p, mid, false) and
|
||||
readStep(mid, _, node) and
|
||||
read(mid, _, node) and
|
||||
read = true
|
||||
)
|
||||
or
|
||||
// flow through: no prior read
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArgCand(p, arg, false) and
|
||||
argumentValueFlowsThroughCand(arg, node, read)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArgCand(p, arg, read) and
|
||||
argumentValueFlowsThroughCand(arg, node, false)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) {
|
||||
private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
|
||||
parameterValueFlowCand(p, arg, read)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) {
|
||||
predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
|
||||
parameterValueFlowCand(p, n.getPreUpdateNode(), false)
|
||||
}
|
||||
|
||||
@@ -360,7 +443,7 @@ private module Cached {
|
||||
* `read` indicates whether it is contents of `p` that can flow to the return
|
||||
* node.
|
||||
*/
|
||||
predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) {
|
||||
predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
|
||||
exists(ReturnNode ret |
|
||||
parameterValueFlowCand(p, ret, read) and
|
||||
kind = ret.getKind()
|
||||
@@ -369,9 +452,9 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argumentValueFlowsThroughCand0(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read
|
||||
DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
|
||||
) {
|
||||
exists(ParameterNode param | viableParamArg(call, param, arg) |
|
||||
exists(ParamNode param | viableParamArg(call, param, arg) |
|
||||
parameterValueFlowReturnCand(param, kind, read)
|
||||
)
|
||||
}
|
||||
@@ -382,14 +465,14 @@ private module Cached {
|
||||
*
|
||||
* `read` indicates whether it is contents of `arg` that can flow to `out`.
|
||||
*/
|
||||
predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) {
|
||||
predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
argumentValueFlowsThroughCand0(call, arg, kind, read) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
predicate cand(ParameterNode p, Node n) {
|
||||
predicate cand(ParamNode p, Node n) {
|
||||
parameterValueFlowCand(p, n, _) and
|
||||
(
|
||||
parameterValueFlowReturnCand(p, _, _)
|
||||
@@ -416,21 +499,21 @@ private module Cached {
|
||||
* If a read step was taken, then `read` captures the `Content`, the
|
||||
* container type, and the content type.
|
||||
*/
|
||||
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) {
|
||||
predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
|
||||
parameterValueFlow0(p, node, read) and
|
||||
if node instanceof CastingNode
|
||||
then
|
||||
// normal flow through
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getNodeType(p), getNodeType(node))
|
||||
compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
|
||||
or
|
||||
// getter
|
||||
compatibleTypes(read.getContentType(), getNodeType(node))
|
||||
compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) {
|
||||
private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
|
||||
p = node and
|
||||
Cand::cand(p, _) and
|
||||
read = TReadStepTypesNone()
|
||||
@@ -447,7 +530,7 @@ private module Cached {
|
||||
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
|
||||
read.getContentType()) and
|
||||
Cand::parameterValueFlowReturnCand(p, _, true) and
|
||||
compatibleTypes(getNodeType(p), read.getContainerType())
|
||||
compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
|
||||
)
|
||||
or
|
||||
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
|
||||
@@ -455,34 +538,32 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0_0(
|
||||
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read
|
||||
ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
|
||||
) {
|
||||
// flow through: no prior read
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArg(p, arg, mustBeNone) and
|
||||
argumentValueFlowsThrough(arg, read, node)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArg(p, arg, read) and
|
||||
argumentValueFlowsThrough(arg, mustBeNone, node)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowArg(
|
||||
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
|
||||
) {
|
||||
private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
|
||||
parameterValueFlow(p, arg, read) and
|
||||
Cand::argumentValueFlowsThroughCand(arg, _, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argumentValueFlowsThrough0(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read
|
||||
DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
|
||||
) {
|
||||
exists(ParameterNode param | viableParamArg(call, param, arg) |
|
||||
exists(ParamNode param | viableParamArg(call, param, arg) |
|
||||
parameterValueFlowReturn(param, kind, read)
|
||||
)
|
||||
}
|
||||
@@ -496,18 +577,18 @@ private module Cached {
|
||||
* container type, and the content type.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) {
|
||||
predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
argumentValueFlowsThrough0(call, arg, kind, read) and
|
||||
out = getAnOutNode(call, kind)
|
||||
|
|
||||
// normal flow through
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getNodeType(arg), getNodeType(out))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
|
||||
or
|
||||
// getter
|
||||
compatibleTypes(getNodeType(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getNodeType(out))
|
||||
compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,7 +597,7 @@ private module Cached {
|
||||
* value-preserving steps and a single read step, not taking call
|
||||
* contexts into account, thus representing a getter-step.
|
||||
*/
|
||||
predicate getterStep(ArgumentNode arg, Content c, Node out) {
|
||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||
}
|
||||
|
||||
@@ -529,7 +610,7 @@ private module Cached {
|
||||
* container type, and the content type.
|
||||
*/
|
||||
private predicate parameterValueFlowReturn(
|
||||
ParameterNode p, ReturnKind kind, ReadStepTypesOption read
|
||||
ParamNode p, ReturnKind kind, ReadStepTypesOption read
|
||||
) {
|
||||
exists(ReturnNode ret |
|
||||
parameterValueFlow(p, ret, read) and
|
||||
@@ -553,7 +634,7 @@ private module Cached {
|
||||
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
|
||||
mayBenefitFromCallContext(call, callable)
|
||||
or
|
||||
callable = call.getEnclosingCallable() and
|
||||
callEnclosingCallable(call, callable) and
|
||||
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
|
||||
}
|
||||
|
||||
@@ -611,7 +692,7 @@ private module Cached {
|
||||
mayBenefitFromCallContextExt(call, _) and
|
||||
c = viableCallableExt(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and
|
||||
tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -635,8 +716,7 @@ private module Cached {
|
||||
* Holds if `p` can flow to the pre-update node associated with post-update
|
||||
* node `n`, in the same callable, using only value-preserving steps.
|
||||
*/
|
||||
cached
|
||||
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
|
||||
private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||
}
|
||||
|
||||
@@ -644,9 +724,9 @@ private module Cached {
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
readStep(_, c, _) and
|
||||
contentType = getNodeType(node1) and
|
||||
containerType = getNodeType(node2)
|
||||
read(_, c, _) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
@@ -654,12 +734,15 @@ private module Cached {
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readStep(n2, c, n1) and
|
||||
contentType = getNodeType(n1) and
|
||||
containerType = getNodeType(n2)
|
||||
read(n2, c, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||
* `f`.
|
||||
@@ -678,8 +761,9 @@ private module Cached {
|
||||
* are aliases. A typical example is a function returning `this`, implementing a fluent
|
||||
* interface.
|
||||
*/
|
||||
cached
|
||||
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) {
|
||||
private predicate reverseStepThroughInputOutputAlias(
|
||||
PostUpdateNode fromNode, PostUpdateNode toNode
|
||||
) {
|
||||
exists(Node fromPre, Node toPre |
|
||||
fromPre = fromNode.getPreUpdateNode() and
|
||||
toPre = toNode.getPreUpdateNode()
|
||||
@@ -688,14 +772,20 @@ private module Cached {
|
||||
// Does the language-specific simpleLocalFlowStep already model flow
|
||||
// from function input to output?
|
||||
fromPre = getAnOutNode(c, _) and
|
||||
toPre.(ArgumentNode).argumentOf(c, _) and
|
||||
simpleLocalFlowStep(toPre.(ArgumentNode), fromPre)
|
||||
toPre.(ArgNode).argumentOf(c, _) and
|
||||
simpleLocalFlowStep(toPre.(ArgNode), fromPre)
|
||||
)
|
||||
or
|
||||
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate simpleLocalFlowStepExt(Node node1, Node node2) {
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
@@ -704,7 +794,7 @@ private module Cached {
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -726,12 +816,12 @@ private module Cached {
|
||||
cached
|
||||
newtype TLocalFlowCallContext =
|
||||
TAnyLocalCall() or
|
||||
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) }
|
||||
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
|
||||
|
||||
cached
|
||||
newtype TReturnKindExt =
|
||||
TValueReturn(ReturnKind kind) or
|
||||
TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) }
|
||||
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
|
||||
cached
|
||||
newtype TBooleanOption =
|
||||
@@ -761,23 +851,15 @@ private module Cached {
|
||||
* A `Node` at which a cast can occur such that the type should be checked.
|
||||
*/
|
||||
class CastingNode extends Node {
|
||||
CastingNode() {
|
||||
this instanceof ParameterNode or
|
||||
this instanceof CastNode or
|
||||
this instanceof OutNodeExt or
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
readStep(_, _, this)
|
||||
}
|
||||
CastingNode() { castingNode(this) }
|
||||
}
|
||||
|
||||
private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
) {
|
||||
readStep(n1, c, n2) and
|
||||
container = getNodeType(n1) and
|
||||
content = getNodeType(n2)
|
||||
read(n1, c, n2) and
|
||||
container = getNodeDataFlowType(n1) and
|
||||
content = getNodeDataFlowType(n2)
|
||||
}
|
||||
|
||||
private newtype TReadStepTypesOption =
|
||||
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override string toString() { result = "CcSomeCall" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
|
||||
exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { any() }
|
||||
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable)
|
||||
exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
|
||||
else result instanceof LocalCallContextAny
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class ParamNode extends Node {
|
||||
ParamNode() { parameterNode(this, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* (zero-based) position.
|
||||
*/
|
||||
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
class ArgNode extends Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
|
||||
*/
|
||||
class ReturnNodeExt extends Node {
|
||||
ReturnNodeExt() {
|
||||
this instanceof ReturnNode or
|
||||
parameterValueFlowsToPreUpdate(_, this)
|
||||
}
|
||||
ReturnNodeExt() { returnNodeExt(this, _) }
|
||||
|
||||
/** Gets the kind of this returned value. */
|
||||
ReturnKindExt getKind() {
|
||||
result = TValueReturn(this.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParameterNode p, int pos |
|
||||
parameterValueFlowsToPreUpdate(p, this) and
|
||||
p.isParameterOf(_, pos) and
|
||||
result = TParamUpdate(pos)
|
||||
)
|
||||
}
|
||||
ReturnKindExt getKind() { returnNodeExt(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
|
||||
* or a post-update node associated with a call argument.
|
||||
*/
|
||||
class OutNodeExt extends Node {
|
||||
OutNodeExt() {
|
||||
this instanceof OutNode
|
||||
or
|
||||
this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
|
||||
}
|
||||
OutNodeExt() { outNodeExt(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
|
||||
abstract string toString();
|
||||
|
||||
/** Gets a node corresponding to data flow out of `call`. */
|
||||
abstract OutNodeExt getAnOutNode(DataFlowCall call);
|
||||
final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
|
||||
}
|
||||
|
||||
class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
ReturnKind getKind() { result = kind }
|
||||
|
||||
override string toString() { result = kind.toString() }
|
||||
|
||||
override OutNodeExt getAnOutNode(DataFlowCall call) {
|
||||
result = getAnOutNode(call, this.getKind())
|
||||
}
|
||||
}
|
||||
|
||||
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
int getPosition() { result = pos }
|
||||
|
||||
override string toString() { result = "param update " + pos }
|
||||
|
||||
override OutNodeExt getAnOutNode(DataFlowCall call) {
|
||||
exists(ArgumentNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, this.getPosition())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A callable tagged with a relevant return kind. */
|
||||
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlowCallable getNodeEnclosingCallable(Node n) {
|
||||
exists(Node n0 |
|
||||
pragma[only_bind_into](n0) = n and
|
||||
pragma[only_bind_into](result) = n0.getEnclosingCallable()
|
||||
)
|
||||
nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
|
||||
}
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
pragma[inline]
|
||||
DataFlowType getNodeDataFlowType(Node n) {
|
||||
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
|
||||
cc instanceof CallContextAny and callable = viableCallableExt(call)
|
||||
or
|
||||
exists(DataFlowCallable c0, DataFlowCall call0 |
|
||||
call0.getEnclosingCallable() = callable and
|
||||
callEnclosingCallable(call0, callable) and
|
||||
cc = TReturn(c0, call0) and
|
||||
c0 = prunedViableImplInCallContextReverse(call0, call)
|
||||
)
|
||||
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
|
||||
result = viableCallableExt(call) and cc instanceof CallContextReturn
|
||||
}
|
||||
|
||||
predicate read = readStep/3;
|
||||
|
||||
/** An optional Boolean value. */
|
||||
class BooleanOption extends TBooleanOption {
|
||||
string toString() {
|
||||
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
|
||||
TypedContent getHead() { this = TFrontHead(result) }
|
||||
|
||||
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) }
|
||||
predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
|
||||
@@ -4,71 +4,48 @@ private import semmle.code.java.dataflow.FlowSummary
|
||||
private import semmle.code.java.dataflow.TypeFlow
|
||||
private import DataFlowPrivate
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TNode =
|
||||
TExprNode(Expr e) {
|
||||
not e.getType() instanceof VoidType and
|
||||
not e.getParent*() instanceof Annotation
|
||||
} or
|
||||
TExplicitParameterNode(Parameter p) {
|
||||
exists(p.getCallable().getBody()) or p.getCallable() instanceof SummarizedCallable
|
||||
} or
|
||||
TImplicitVarargsArray(Call c) {
|
||||
c.getCallee().isVarargs() and
|
||||
not exists(Argument arg | arg.getCall() = c and arg.isExplicitVarargsArray())
|
||||
} or
|
||||
TInstanceParameterNode(Callable c) {
|
||||
(exists(c.getBody()) or c instanceof SummarizedCallable) and
|
||||
not c.isStatic()
|
||||
} or
|
||||
TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or
|
||||
TMallocNode(ClassInstanceExpr cie) or
|
||||
TExplicitExprPostUpdate(Expr e) {
|
||||
explicitInstanceArgument(_, e)
|
||||
or
|
||||
e instanceof Argument and not e.getType() instanceof ImmutableType
|
||||
or
|
||||
exists(FieldAccess fa | fa.getField() instanceof InstanceField and e = fa.getQualifier())
|
||||
or
|
||||
exists(ArrayAccess aa | e = aa.getArray())
|
||||
} or
|
||||
TImplicitExprPostUpdate(InstanceAccessExt ia) {
|
||||
implicitInstanceArgument(_, ia)
|
||||
or
|
||||
exists(FieldAccess fa |
|
||||
fa.getField() instanceof InstanceField and ia.isImplicitFieldQualifier(fa)
|
||||
)
|
||||
} or
|
||||
TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
|
||||
FlowSummaryImpl::Private::summaryNodeRange(c, state)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate summaryOutNodeCached(DataFlowCall c, Node out) {
|
||||
FlowSummaryImpl::Private::summaryOutNode(c, out, _)
|
||||
newtype TNode =
|
||||
TExprNode(Expr e) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
not e.getType() instanceof VoidType and
|
||||
not e.getParent*() instanceof Annotation
|
||||
} or
|
||||
TExplicitParameterNode(Parameter p) {
|
||||
exists(p.getCallable().getBody()) or p.getCallable() instanceof SummarizedCallable
|
||||
} or
|
||||
TImplicitVarargsArray(Call c) {
|
||||
c.getCallee().isVarargs() and
|
||||
not exists(Argument arg | arg.getCall() = c and arg.isExplicitVarargsArray())
|
||||
} or
|
||||
TInstanceParameterNode(Callable c) {
|
||||
(exists(c.getBody()) or c instanceof SummarizedCallable) and
|
||||
not c.isStatic()
|
||||
} or
|
||||
TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or
|
||||
TMallocNode(ClassInstanceExpr cie) or
|
||||
TExplicitExprPostUpdate(Expr e) {
|
||||
explicitInstanceArgument(_, e)
|
||||
or
|
||||
e instanceof Argument and not e.getType() instanceof ImmutableType
|
||||
or
|
||||
exists(FieldAccess fa | fa.getField() instanceof InstanceField and e = fa.getQualifier())
|
||||
or
|
||||
exists(ArrayAccess aa | e = aa.getArray())
|
||||
} or
|
||||
TImplicitExprPostUpdate(InstanceAccessExt ia) {
|
||||
implicitInstanceArgument(_, ia)
|
||||
or
|
||||
exists(FieldAccess fa |
|
||||
fa.getField() instanceof InstanceField and ia.isImplicitFieldQualifier(fa)
|
||||
)
|
||||
} or
|
||||
TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
|
||||
FlowSummaryImpl::Private::summaryNodeRange(c, state)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate summaryArgumentNodeCached(DataFlowCall c, Node arg, int i) {
|
||||
FlowSummaryImpl::Private::summaryArgumentNode(c, arg, i)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate summaryPostUpdateNodeCached(Node post, ParameterNode pre) {
|
||||
FlowSummaryImpl::Private::summaryPostUpdateNode(post, pre)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate summaryReturnNodeCached(Node ret) {
|
||||
FlowSummaryImpl::Private::summaryReturnNode(ret, _)
|
||||
}
|
||||
}
|
||||
|
||||
private import Cached
|
||||
|
||||
private predicate explicitInstanceArgument(Call call, Expr instarg) {
|
||||
call instanceof MethodAccess and
|
||||
instarg = call.getQualifier() and
|
||||
@@ -404,13 +381,15 @@ module Private {
|
||||
override string toString() { result = "[summary] " + state + " in " + c }
|
||||
|
||||
/** Holds if this summary node is the `i`th argument of `call`. */
|
||||
predicate isArgumentOf(DataFlowCall call, int i) { summaryArgumentNodeCached(call, this, i) }
|
||||
predicate isArgumentOf(DataFlowCall call, int i) {
|
||||
FlowSummaryImpl::Private::summaryArgumentNode(call, this, i)
|
||||
}
|
||||
|
||||
/** Holds if this summary node is a return node. */
|
||||
predicate isReturn() { summaryReturnNodeCached(this) }
|
||||
predicate isReturn() { FlowSummaryImpl::Private::summaryReturnNode(this, _) }
|
||||
|
||||
/** Holds if this summary node is an out node for `call`. */
|
||||
predicate isOut(DataFlowCall call) { summaryOutNodeCached(call, this) }
|
||||
predicate isOut(DataFlowCall call) { FlowSummaryImpl::Private::summaryOutNode(call, this, _) }
|
||||
}
|
||||
|
||||
SummaryNode getSummaryNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
|
||||
@@ -439,7 +418,7 @@ private class MallocNode extends Node, TMallocNode {
|
||||
private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode {
|
||||
private Node pre;
|
||||
|
||||
SummaryPostUpdateNode() { summaryPostUpdateNodeCached(this, pre) }
|
||||
SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, pre) }
|
||||
|
||||
override Node getPreUpdateNode() { result = pre }
|
||||
}
|
||||
|
||||
@@ -284,7 +284,6 @@ private class ConstantBooleanArgumentNode extends ArgumentNode, ExprNode {
|
||||
/**
|
||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||
*/
|
||||
cached
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
exists(
|
||||
ExplicitParameterNode paramNode, ConstantBooleanArgumentNode arg, SsaImplicitInit param,
|
||||
|
||||
@@ -11,6 +11,7 @@ private import semmle.code.java.dataflow.FlowSteps
|
||||
private import semmle.code.java.dataflow.FlowSummary
|
||||
import semmle.code.java.dataflow.InstanceAccess
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import TaintTrackingUtil as TaintTrackingUtil
|
||||
import DataFlowNodes::Public
|
||||
|
||||
/** Holds if `n` is an access to an unqualified `this` at `cfgnode`. */
|
||||
@@ -112,6 +113,7 @@ predicate localFlowStep(Node node1, Node node2) {
|
||||
*/
|
||||
cached
|
||||
predicate simpleLocalFlowStep(Node node1, Node node2) {
|
||||
TaintTrackingUtil::forceCachingInSameStage() and
|
||||
// Variable flow steps through adjacent def-use and use-use pairs.
|
||||
exists(SsaExplicitUpdate upd |
|
||||
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() or
|
||||
|
||||
@@ -29,55 +29,69 @@ predicate localExprTaint(Expr src, Expr sink) {
|
||||
localTaint(DataFlow::exprNode(src), DataFlow::exprNode(sink))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `src` to `sink`.
|
||||
*/
|
||||
predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
DataFlow::localFlowStep(src, sink) or
|
||||
localAdditionalTaintStep(src, sink) or
|
||||
// Simple flow through library code is included in the exposed local
|
||||
// step relation, even though flow is technically inter-procedural
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStep(src, sink, false)
|
||||
cached
|
||||
private module Cached {
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
cached
|
||||
predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() }
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `src` to `sink`.
|
||||
*/
|
||||
cached
|
||||
predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
DataFlow::localFlowStep(src, sink) or
|
||||
localAdditionalTaintStep(src, sink) or
|
||||
// Simple flow through library code is included in the exposed local
|
||||
// step relation, even though flow is technically inter-procedural
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStep(src, sink, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `src` to `sink` excluding
|
||||
* local data flow steps. That is, `src` and `sink` are likely to represent
|
||||
* different objects.
|
||||
*/
|
||||
cached
|
||||
predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
localAdditionalTaintExprStep(src.asExpr(), sink.asExpr())
|
||||
or
|
||||
localAdditionalTaintUpdateStep(src.asExpr(),
|
||||
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
|
||||
or
|
||||
exists(Argument arg |
|
||||
src.asExpr() = arg and
|
||||
arg.isVararg() and
|
||||
sink.(DataFlow::ImplicitVarargsArray).getCall() = arg.getCall()
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional step from `src` to `sink` should be included in all
|
||||
* global taint flow configurations.
|
||||
*/
|
||||
cached
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
localAdditionalTaintStep(src, sink) or
|
||||
any(AdditionalTaintStep a).step(src, sink)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` should be a sanitizer in all global taint flow configurations
|
||||
* but not in local taint.
|
||||
*/
|
||||
cached
|
||||
predicate defaultTaintSanitizer(DataFlow::Node node) {
|
||||
// Ignore paths through test code.
|
||||
node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass or
|
||||
node.asExpr() instanceof ValidatedVariableAccess
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `src` to `sink` excluding
|
||||
* local data flow steps. That is, `src` and `sink` are likely to represent
|
||||
* different objects.
|
||||
*/
|
||||
predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
localAdditionalTaintExprStep(src.asExpr(), sink.asExpr())
|
||||
or
|
||||
localAdditionalTaintUpdateStep(src.asExpr(),
|
||||
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
|
||||
or
|
||||
exists(Argument arg |
|
||||
src.asExpr() = arg and
|
||||
arg.isVararg() and
|
||||
sink.(DataFlow::ImplicitVarargsArray).getCall() = arg.getCall()
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional step from `src` to `sink` should be included in all
|
||||
* global taint flow configurations.
|
||||
*/
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
|
||||
localAdditionalTaintStep(src, sink) or
|
||||
any(AdditionalTaintStep a).step(src, sink)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` should be a sanitizer in all global taint flow configurations
|
||||
* but not in local taint.
|
||||
*/
|
||||
predicate defaultTaintSanitizer(DataFlow::Node node) {
|
||||
// Ignore paths through test code.
|
||||
node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass or
|
||||
node.asExpr() instanceof ValidatedVariableAccess
|
||||
}
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `src` to `sink` excluding
|
||||
|
||||
@@ -3,19 +3,60 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.FlowSteps
|
||||
|
||||
/**
|
||||
* The type `com.esotericsoftware.kryo.Kryo`.
|
||||
*/
|
||||
class Kryo extends RefType {
|
||||
Kryo() { this.hasQualifiedName("com.esotericsoftware.kryo", "Kryo") }
|
||||
Kryo() {
|
||||
hasQualifiedName("com.esotericsoftware.kryo", "Kryo") or
|
||||
hasQualifiedName("com.esotericsoftware.kryo5", "Kryo")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Kryo input stream.
|
||||
*/
|
||||
class KryoInput extends RefType {
|
||||
KryoInput() { this.hasQualifiedName("com.esotericsoftware.kryo.io", "Input") }
|
||||
KryoInput() {
|
||||
hasQualifiedName("com.esotericsoftware.kryo.io", "Input") or
|
||||
hasQualifiedName("com.esotericsoftware.kryo5.io", "Input")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Kryo pool.
|
||||
*/
|
||||
class KryoPool extends RefType {
|
||||
KryoPool() {
|
||||
hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool") or
|
||||
hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Kryo pool builder.
|
||||
*/
|
||||
class KryoPoolBuilder extends RefType {
|
||||
KryoPoolBuilder() {
|
||||
hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool$Builder") or
|
||||
hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool$Builder")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Kryo pool builder method used in a fluent API call chain.
|
||||
*/
|
||||
class KryoPoolBuilderMethod extends Method {
|
||||
KryoPoolBuilderMethod() {
|
||||
getDeclaringType() instanceof KryoPoolBuilder and
|
||||
(
|
||||
getReturnType() instanceof KryoPoolBuilder or
|
||||
getReturnType() instanceof KryoPool
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,3 +86,13 @@ class KryoEnableWhiteListing extends MethodAccess {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A KryoPool method that uses a Kryo instance.
|
||||
*/
|
||||
class KryoPoolRunMethod extends Method {
|
||||
KryoPoolRunMethod() {
|
||||
getDeclaringType() instanceof KryoPool and
|
||||
hasName("run")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import semmle.code.java.Reflection
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.DataFlow5
|
||||
import semmle.code.java.dataflow.FlowSteps
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
/**
|
||||
* A `@com.fasterxml.jackson.annotation.JsonIgnore` annoation.
|
||||
@@ -28,7 +29,7 @@ abstract class JacksonSerializableType extends Type { }
|
||||
* A method used for serializing objects using Jackson. The final parameter is the object to be
|
||||
* serialized.
|
||||
*/
|
||||
library class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
|
||||
private class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
|
||||
JacksonWriteValueMethod() {
|
||||
(
|
||||
getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectWriter") or
|
||||
@@ -50,8 +51,20 @@ library class JacksonWriteValueMethod extends Method, TaintPreservingCallable {
|
||||
}
|
||||
}
|
||||
|
||||
private class JacksonReadValueMethod extends Method, TaintPreservingCallable {
|
||||
JacksonReadValueMethod() {
|
||||
(
|
||||
getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectReader") or
|
||||
getDeclaringType().hasQualifiedName("com.fasterxml.jackson.databind", "ObjectMapper")
|
||||
) and
|
||||
hasName(["readValue", "readValues"])
|
||||
}
|
||||
|
||||
override predicate returnsTaintFrom(int arg) { arg = 0 }
|
||||
}
|
||||
|
||||
/** A type whose values are explicitly serialized in a call to a Jackson method. */
|
||||
library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializableType {
|
||||
private class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializableType {
|
||||
ExplicitlyWrittenJacksonSerializableType() {
|
||||
exists(MethodAccess ma |
|
||||
// A call to a Jackson write method...
|
||||
@@ -63,7 +76,7 @@ library class ExplicitlyWrittenJacksonSerializableType extends JacksonSerializab
|
||||
}
|
||||
|
||||
/** A type used in a `JacksonSerializableField` declaration. */
|
||||
library class FieldReferencedJacksonSerializableType extends JacksonSerializableType {
|
||||
private class FieldReferencedJacksonSerializableType extends JacksonSerializableType {
|
||||
FieldReferencedJacksonSerializableType() {
|
||||
exists(JacksonSerializableField f | usesType(f.getType(), this))
|
||||
}
|
||||
@@ -96,17 +109,24 @@ private class TypeLiteralToJacksonDatabindFlowConfiguration extends DataFlow5::C
|
||||
}
|
||||
|
||||
/** A type whose values are explicitly deserialized in a call to a Jackson method. */
|
||||
library class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializableType {
|
||||
private class ExplicitlyReadJacksonDeserializableType extends JacksonDeserializableType {
|
||||
ExplicitlyReadJacksonDeserializableType() {
|
||||
exists(TypeLiteralToJacksonDatabindFlowConfiguration conf |
|
||||
usesType(conf.getSourceWithFlowToJacksonDatabind().getTypeName().getType(), this)
|
||||
)
|
||||
or
|
||||
exists(MethodAccess ma |
|
||||
// A call to a Jackson read method...
|
||||
ma.getMethod() instanceof JacksonReadValueMethod and
|
||||
// ...where `this` is used in the final argument, indicating that this type will be deserialized.
|
||||
usesType(ma.getArgument(ma.getNumArgument() - 1).getType(), this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A type used in a `JacksonDeserializableField` declaration. */
|
||||
library class FieldReferencedJacksonDeSerializableType extends JacksonDeserializableType {
|
||||
FieldReferencedJacksonDeSerializableType() {
|
||||
private class FieldReferencedJacksonDeserializableType extends JacksonDeserializableType {
|
||||
FieldReferencedJacksonDeserializableType() {
|
||||
exists(JacksonDeserializableField f | usesType(f.getType(), this))
|
||||
}
|
||||
}
|
||||
@@ -135,6 +155,21 @@ class JacksonDeserializableField extends DeserializableField {
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to a field that may be deserialized using the Jackson JSON framework. */
|
||||
private class JacksonDeserializableFieldAccess extends FieldAccess {
|
||||
JacksonDeserializableFieldAccess() { getField() instanceof JacksonDeserializableField }
|
||||
}
|
||||
|
||||
/**
|
||||
* When an object is deserialized by the Jackson JSON framework using a tainted input source,
|
||||
* the fields that the framework deserialized are themselves tainted input data.
|
||||
*/
|
||||
private class JacksonDeserializedTaintStep extends AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
DataFlow::getFieldQualifier(node2.asExpr().(JacksonDeserializableFieldAccess)) = node1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the `addMixInAnnotations` or `addMixIn` Jackson method.
|
||||
*
|
||||
@@ -239,3 +274,13 @@ class JacksonMixedInCallable extends Callable {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class JacksonModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"com.fasterxml.jackson.databind;ObjectMapper;true;valueToTree;;;Argument[0];ReturnValue;taint",
|
||||
"com.fasterxml.jackson.databind;ObjectMapper;true;convertValue;;;Argument[0];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,65 @@ class SafeKryo extends DataFlow2::Configuration {
|
||||
ma.getMethod() instanceof KryoReadObjectMethod
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
stepKryoPoolBuilderFactoryArgToConstructor(node1, node2) or
|
||||
stepKryoPoolRunMethodAccessQualifierToFunctionalArgument(node1, node2) or
|
||||
stepKryoPoolBuilderChainMethod(node1, node2) or
|
||||
stepKryoPoolBorrowMethod(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds when a functional expression is used to create a `KryoPool.Builder`.
|
||||
* Eg. `new KryoPool.Builder(() -> new Kryo())`
|
||||
*/
|
||||
private predicate stepKryoPoolBuilderFactoryArgToConstructor(
|
||||
DataFlow::Node node1, DataFlow::Node node2
|
||||
) {
|
||||
exists(ConstructorCall cc, FunctionalExpr fe |
|
||||
cc.getConstructedType() instanceof KryoPoolBuilder and
|
||||
fe.asMethod().getBody().getAStmt().(ReturnStmt).getResult() = node1.asExpr() and
|
||||
node2.asExpr() = cc and
|
||||
cc.getArgument(0) = fe
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds when a `KryoPool.run` is called to use a `Kryo` instance.
|
||||
* Eg. `pool.run(kryo -> ...)`
|
||||
*/
|
||||
private predicate stepKryoPoolRunMethodAccessQualifierToFunctionalArgument(
|
||||
DataFlow::Node node1, DataFlow::Node node2
|
||||
) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof KryoPoolRunMethod and
|
||||
node1.asExpr() = ma.getQualifier() and
|
||||
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds when a `KryoPool.Builder` method is called fluently.
|
||||
*/
|
||||
private predicate stepKryoPoolBuilderChainMethod(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() instanceof KryoPoolBuilderMethod and
|
||||
ma = node2.asExpr() and
|
||||
ma.getQualifier() = node1.asExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds when a `KryoPool.borrow` method is called.
|
||||
*/
|
||||
private predicate stepKryoPoolBorrowMethod(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma |
|
||||
ma.getMethod() =
|
||||
any(Method m | m.getDeclaringType() instanceof KryoPool and m.hasName("borrow")) and
|
||||
node1.asExpr() = ma.getQualifier() and
|
||||
node2.asExpr() = ma
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
|
||||
|
||||
@@ -36,7 +36,10 @@ abstract class ParserConfig extends MethodAccess {
|
||||
*/
|
||||
predicate disables(Expr e) {
|
||||
this.getArgument(0) = e and
|
||||
this.getArgument(1).(BooleanLiteral).getBooleanValue() = false
|
||||
(
|
||||
this.getArgument(1).(BooleanLiteral).getBooleanValue() = false or
|
||||
this.getArgument(1).(FieldAccess).getField().hasQualifiedName("java.lang", "Boolean", "FALSE")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,7 +47,10 @@ abstract class ParserConfig extends MethodAccess {
|
||||
*/
|
||||
predicate enables(Expr e) {
|
||||
this.getArgument(0) = e and
|
||||
this.getArgument(1).(BooleanLiteral).getBooleanValue() = true
|
||||
(
|
||||
this.getArgument(1).(BooleanLiteral).getBooleanValue() = true or
|
||||
this.getArgument(1).(FieldAccess).getField().hasQualifiedName("java.lang", "Boolean", "TRUE")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
edges
|
||||
| JythonInjection.java:28:23:28:50 | getParameter(...) : String | JythonInjection.java:36:30:36:33 | code |
|
||||
| JythonInjection.java:53:23:53:50 | getParameter(...) : String | JythonInjection.java:58:44:58:47 | code |
|
||||
| JythonInjection.java:73:23:73:50 | getParameter(...) : String | JythonInjection.java:81:35:81:38 | code |
|
||||
| JythonInjection.java:97:23:97:50 | getParameter(...) : String | JythonInjection.java:106:61:106:75 | getBytes(...) |
|
||||
nodes
|
||||
| JythonInjection.java:28:23:28:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JythonInjection.java:36:30:36:33 | code | semmle.label | code |
|
||||
| JythonInjection.java:53:23:53:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JythonInjection.java:58:44:58:47 | code | semmle.label | code |
|
||||
| JythonInjection.java:73:23:73:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JythonInjection.java:81:35:81:38 | code | semmle.label | code |
|
||||
| JythonInjection.java:97:23:97:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| JythonInjection.java:106:61:106:75 | getBytes(...) | semmle.label | getBytes(...) |
|
||||
| JythonInjection.java:131:40:131:63 | getInputStream(...) | semmle.label | getInputStream(...) |
|
||||
#select
|
||||
| JythonInjection.java:36:13:36:34 | exec(...) | JythonInjection.java:28:23:28:50 | getParameter(...) : String | JythonInjection.java:36:30:36:33 | code | Jython evaluate $@. | JythonInjection.java:28:23:28:50 | getParameter(...) | user input |
|
||||
| JythonInjection.java:58:27:58:48 | eval(...) | JythonInjection.java:53:23:53:50 | getParameter(...) : String | JythonInjection.java:58:44:58:47 | code | Jython evaluate $@. | JythonInjection.java:53:23:53:50 | getParameter(...) | user input |
|
||||
| JythonInjection.java:81:13:81:39 | runsource(...) | JythonInjection.java:73:23:73:50 | getParameter(...) : String | JythonInjection.java:81:35:81:38 | code | Jython evaluate $@. | JythonInjection.java:73:23:73:50 | getParameter(...) | user input |
|
||||
| JythonInjection.java:106:29:106:134 | makeCode(...) | JythonInjection.java:97:23:97:50 | getParameter(...) : String | JythonInjection.java:106:61:106:75 | getBytes(...) | Jython evaluate $@. | JythonInjection.java:97:23:97:50 | getParameter(...) | user input |
|
||||
| JythonInjection.java:131:29:131:109 | compile(...) | JythonInjection.java:131:40:131:63 | getInputStream(...) | JythonInjection.java:131:40:131:63 | getInputStream(...) | Jython evaluate $@. | JythonInjection.java:131:40:131:63 | getInputStream(...) | user input |
|
||||
@@ -0,0 +1,144 @@
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.python.core.BytecodeLoader;
|
||||
import org.python.core.Py;
|
||||
import org.python.core.PyCode;
|
||||
import org.python.core.PyException;
|
||||
import org.python.core.PyObject;
|
||||
import org.python.util.InteractiveInterpreter;
|
||||
import org.python.util.PythonInterpreter;
|
||||
|
||||
public class JythonInjection extends HttpServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public JythonInjection() {
|
||||
super();
|
||||
}
|
||||
|
||||
// BAD: allow execution of arbitrary Python code
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
String code = request.getParameter("code");
|
||||
PythonInterpreter interpreter = null;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
interpreter = new PythonInterpreter();
|
||||
interpreter.setOut(out);
|
||||
interpreter.setErr(out);
|
||||
interpreter.exec(code);
|
||||
out.flush();
|
||||
|
||||
response.getWriter().print(out.toString());
|
||||
} catch(PyException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
if (interpreter != null) {
|
||||
interpreter.close();
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
// BAD: allow execution of arbitrary Python code
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
String code = request.getParameter("code");
|
||||
PythonInterpreter interpreter = null;
|
||||
|
||||
try {
|
||||
interpreter = new PythonInterpreter();
|
||||
PyObject py = interpreter.eval(code);
|
||||
|
||||
response.getWriter().print(py.toString());
|
||||
} catch(PyException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
if (interpreter != null) {
|
||||
interpreter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BAD: allow arbitrary Jython expression to run
|
||||
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
String code = request.getParameter("code");
|
||||
InteractiveInterpreter interpreter = null;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
interpreter = new InteractiveInterpreter();
|
||||
interpreter.setOut(out);
|
||||
interpreter.setErr(out);
|
||||
interpreter.runsource(code);
|
||||
out.flush();
|
||||
|
||||
response.getWriter().print(out.toString());
|
||||
} catch(PyException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
if (interpreter != null) {
|
||||
interpreter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BAD: load arbitrary class file to execute
|
||||
protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
String code = request.getParameter("code");
|
||||
PythonInterpreter interpreter = null;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
interpreter = new PythonInterpreter();
|
||||
interpreter.setOut(out);
|
||||
interpreter.setErr(out);
|
||||
|
||||
PyCode pyCode = BytecodeLoader.makeCode("test", code.getBytes(), getServletContext().getRealPath("/com/example/test.pyc"));
|
||||
interpreter.exec(pyCode);
|
||||
out.flush();
|
||||
|
||||
response.getWriter().print(out.toString());
|
||||
} catch(PyException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
if (interpreter != null) {
|
||||
interpreter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BAD: Compile Python code to execute
|
||||
protected void doHead(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
PythonInterpreter interpreter = null;
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
interpreter = new PythonInterpreter();
|
||||
interpreter.setOut(out);
|
||||
interpreter.setErr(out);
|
||||
|
||||
PyCode pyCode = Py.compile(request.getInputStream(), "Test.py", org.python.core.CompileMode.eval);
|
||||
interpreter.exec(pyCode);
|
||||
out.flush();
|
||||
|
||||
response.getWriter().print(out.toString());
|
||||
} catch(PyException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
if (interpreter != null) {
|
||||
interpreter.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-094/JythonInjection.ql
|
||||
@@ -0,0 +1,91 @@
|
||||
import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mozilla.javascript.ClassShutter;
|
||||
import org.mozilla.javascript.CompilerEnvirons;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.DefiningClassLoader;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.RhinoException;
|
||||
import org.mozilla.javascript.optimizer.ClassCompiler;
|
||||
|
||||
/**
|
||||
* Servlet implementation class RhinoServlet
|
||||
*/
|
||||
public class RhinoServlet extends HttpServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RhinoServlet() {
|
||||
super();
|
||||
}
|
||||
|
||||
// BAD: allow arbitrary Java and JavaScript code to be executed
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
String code = request.getParameter("code");
|
||||
Context ctx = Context.enter();
|
||||
try {
|
||||
Scriptable scope = ctx.initStandardObjects();
|
||||
Object result = ctx.evaluateString(scope, code, "<code>", 1, null);
|
||||
response.getWriter().print(Context.toString(result));
|
||||
} catch(RhinoException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
Context.exit();
|
||||
}
|
||||
}
|
||||
|
||||
// GOOD: enable the safe mode
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
String code = request.getParameter("code");
|
||||
Context ctx = Context.enter();
|
||||
try {
|
||||
Scriptable scope = ctx.initSafeStandardObjects();
|
||||
Object result = ctx.evaluateString(scope, code, "<code>", 1, null);
|
||||
response.getWriter().print(Context.toString(result));
|
||||
} catch(RhinoException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
Context.exit();
|
||||
}
|
||||
}
|
||||
|
||||
// GOOD: enforce a constraint on allowed classes
|
||||
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("text/plain");
|
||||
String code = request.getParameter("code");
|
||||
Context ctx = Context.enter();
|
||||
try {
|
||||
Scriptable scope = ctx.initStandardObjects();
|
||||
ctx.setClassShutter(new ClassShutter() {
|
||||
public boolean visibleToScripts(String className) {
|
||||
return className.startsWith("com.example.");
|
||||
}
|
||||
});
|
||||
|
||||
Object result = ctx.evaluateString(scope, code, "<code>", 1, null);
|
||||
response.getWriter().print(Context.toString(result));
|
||||
} catch(RhinoException ex) {
|
||||
response.getWriter().println(ex.getMessage());
|
||||
} finally {
|
||||
Context.exit();
|
||||
}
|
||||
}
|
||||
|
||||
// BAD: allow arbitrary code to be compiled for subsequent execution
|
||||
protected void doGet2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
String code = request.getParameter("code");
|
||||
ClassCompiler compiler = new ClassCompiler(new CompilerEnvirons());
|
||||
Object[] objs = compiler.compileToClassFiles(code, "/sourceLocation", 1, "mainClassName");
|
||||
}
|
||||
|
||||
// BAD: allow arbitrary code to be loaded for subsequent execution
|
||||
protected void doPost2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
String code = request.getParameter("code");
|
||||
Class clazz = new DefiningClassLoader().defineClass("Powerfunc", code.getBytes());
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
edges
|
||||
| ScriptEngineTest.java:8:44:8:55 | input : String | ScriptEngineTest.java:12:37:12:41 | input |
|
||||
| ScriptEngineTest.java:15:51:15:62 | input : String | ScriptEngineTest.java:19:31:19:35 | input |
|
||||
| ScriptEngineTest.java:23:58:23:69 | input : String | ScriptEngineTest.java:27:31:27:35 | input |
|
||||
| ScriptEngineTest.java:30:46:30:57 | input : String | ScriptEngineTest.java:34:31:34:35 | input |
|
||||
| ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:38:56:38:62 | ...[...] : String |
|
||||
| ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:39:63:39:69 | ...[...] : String |
|
||||
| ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:40:70:40:76 | ...[...] : String |
|
||||
| ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:41:58:41:64 | ...[...] : String |
|
||||
| ScriptEngineTest.java:38:56:38:62 | ...[...] : String | ScriptEngineTest.java:8:44:8:55 | input : String |
|
||||
| ScriptEngineTest.java:39:63:39:69 | ...[...] : String | ScriptEngineTest.java:15:51:15:62 | input : String |
|
||||
| ScriptEngineTest.java:40:70:40:76 | ...[...] : String | ScriptEngineTest.java:23:58:23:69 | input : String |
|
||||
| ScriptEngineTest.java:41:58:41:64 | ...[...] : String | ScriptEngineTest.java:30:46:30:57 | input : String |
|
||||
nodes
|
||||
| ScriptEngineTest.java:8:44:8:55 | input : String | semmle.label | input : String |
|
||||
| ScriptEngineTest.java:12:37:12:41 | input | semmle.label | input |
|
||||
| ScriptEngineTest.java:15:51:15:62 | input : String | semmle.label | input : String |
|
||||
| ScriptEngineTest.java:19:31:19:35 | input | semmle.label | input |
|
||||
| ScriptEngineTest.java:23:58:23:69 | input : String | semmle.label | input : String |
|
||||
| ScriptEngineTest.java:27:31:27:35 | input | semmle.label | input |
|
||||
| ScriptEngineTest.java:30:46:30:57 | input : String | semmle.label | input : String |
|
||||
| ScriptEngineTest.java:34:31:34:35 | input | semmle.label | input |
|
||||
| ScriptEngineTest.java:37:26:37:38 | args : String[] | semmle.label | args : String[] |
|
||||
| ScriptEngineTest.java:38:56:38:62 | ...[...] : String | semmle.label | ...[...] : String |
|
||||
| ScriptEngineTest.java:39:63:39:69 | ...[...] : String | semmle.label | ...[...] : String |
|
||||
| ScriptEngineTest.java:40:70:40:76 | ...[...] : String | semmle.label | ...[...] : String |
|
||||
| ScriptEngineTest.java:41:58:41:64 | ...[...] : String | semmle.label | ...[...] : String |
|
||||
#select
|
||||
| ScriptEngineTest.java:12:19:12:42 | eval(...) | ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:12:37:12:41 | input | ScriptEngine eval $@. | ScriptEngineTest.java:37:26:37:38 | args | user input |
|
||||
| ScriptEngineTest.java:19:19:19:36 | eval(...) | ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:19:31:19:35 | input | ScriptEngine eval $@. | ScriptEngineTest.java:37:26:37:38 | args | user input |
|
||||
| ScriptEngineTest.java:27:19:27:36 | eval(...) | ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:27:31:27:35 | input | ScriptEngine eval $@. | ScriptEngineTest.java:37:26:37:38 | args | user input |
|
||||
| ScriptEngineTest.java:34:19:34:36 | eval(...) | ScriptEngineTest.java:37:26:37:38 | args : String[] | ScriptEngineTest.java:34:31:34:35 | input | ScriptEngine eval $@. | ScriptEngineTest.java:37:26:37:38 | args | user input |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-094/ScriptEngine.ql
|
||||
@@ -1,9 +1,21 @@
|
||||
import javax.script.AbstractScriptEngine;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import jdk.nashorn.api.scripting.NashornScriptEngine;
|
||||
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
||||
import javax.script.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class ScriptEngineTest {
|
||||
public class ScriptEngineTest extends HttpServlet {
|
||||
|
||||
public void testWithScriptEngineReference(String input) throws ScriptException {
|
||||
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
|
||||
@@ -33,26 +45,59 @@ public class ScriptEngineTest {
|
||||
MyCustomScriptEngine engine = (MyCustomScriptEngine) factory.getScriptEngine(new String[] { "-scripting" });
|
||||
Object result = engine.eval(input);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws ScriptException {
|
||||
new ScriptEngineTest().testWithScriptEngineReference(args[0]);
|
||||
new ScriptEngineTest().testNashornWithScriptEngineReference(args[0]);
|
||||
new ScriptEngineTest().testNashornWithNashornScriptEngineReference(args[0]);
|
||||
new ScriptEngineTest().testCustomScriptEngineReference(args[0]);
|
||||
|
||||
public void testScriptEngineCompilable(String input) throws ScriptException {
|
||||
NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
|
||||
Compilable engine = (Compilable) factory.getScriptEngine(new String[] { "-scripting" });
|
||||
CompiledScript script = engine.compile(input);
|
||||
Object result = script.eval();
|
||||
}
|
||||
|
||||
|
||||
public void testScriptEngineGetProgram(String input) throws ScriptException {
|
||||
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
|
||||
ScriptEngine engine = scriptEngineManager.getEngineByName("nashorn");
|
||||
String program = engine.getFactory().getProgram(input);
|
||||
Object result = engine.eval(program);
|
||||
}
|
||||
|
||||
private static class MyCustomScriptEngine extends AbstractScriptEngine {
|
||||
public Object eval(String var1) throws ScriptException {
|
||||
return null;
|
||||
}
|
||||
public Object eval(String var1) throws ScriptException { return null; }
|
||||
|
||||
@Override
|
||||
public ScriptEngineFactory getFactory() { return null; }
|
||||
}
|
||||
|
||||
private static class MyCustomFactory implements ScriptEngineFactory {
|
||||
public MyCustomFactory() {
|
||||
}
|
||||
|
||||
public ScriptEngine getScriptEngine() { return null; }
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngine getScriptEngine() { return null; }
|
||||
|
||||
public ScriptEngine getScriptEngine(String... args) { return null; }
|
||||
|
||||
@Override
|
||||
public String getEngineName() { return null; }
|
||||
|
||||
@Override
|
||||
public String getMethodCallSyntax(final String obj, final String method, final String... args) { return null; }
|
||||
|
||||
@Override
|
||||
public String getProgram(final String... statements) { return null; }
|
||||
}
|
||||
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
try {
|
||||
String code = request.getParameter("code");
|
||||
|
||||
new ScriptEngineTest().testWithScriptEngineReference(code);
|
||||
new ScriptEngineTest().testNashornWithScriptEngineReference(code);
|
||||
new ScriptEngineTest().testNashornWithNashornScriptEngineReference(code);
|
||||
new ScriptEngineTest().testCustomScriptEngineReference(code);
|
||||
new ScriptEngineTest().testScriptEngineCompilable(code);
|
||||
new ScriptEngineTest().testScriptEngineGetProgram(code);
|
||||
} catch (ScriptException se) {
|
||||
throw new IOException(se.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
edges
|
||||
| RhinoServlet.java:28:23:28:50 | getParameter(...) : String | RhinoServlet.java:32:55:32:58 | code |
|
||||
| RhinoServlet.java:81:23:81:50 | getParameter(...) : String | RhinoServlet.java:83:54:83:57 | code |
|
||||
| RhinoServlet.java:88:23:88:50 | getParameter(...) : String | RhinoServlet.java:89:74:89:88 | getBytes(...) |
|
||||
| ScriptEngineTest.java:20:44:20:55 | input : String | ScriptEngineTest.java:24:37:24:41 | input |
|
||||
| ScriptEngineTest.java:27:51:27:62 | input : String | ScriptEngineTest.java:31:31:31:35 | input |
|
||||
| ScriptEngineTest.java:35:58:35:69 | input : String | ScriptEngineTest.java:39:31:39:35 | input |
|
||||
| ScriptEngineTest.java:42:46:42:57 | input : String | ScriptEngineTest.java:46:31:46:35 | input |
|
||||
| ScriptEngineTest.java:49:41:49:52 | input : String | ScriptEngineTest.java:52:42:52:46 | input |
|
||||
| ScriptEngineTest.java:56:41:56:52 | input : String | ScriptEngineTest.java:59:51:59:55 | input |
|
||||
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:93:57:93:60 | code : String |
|
||||
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:94:64:94:67 | code : String |
|
||||
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:95:71:95:74 | code : String |
|
||||
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:96:59:96:62 | code : String |
|
||||
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:97:54:97:57 | code : String |
|
||||
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:98:54:98:57 | code : String |
|
||||
| ScriptEngineTest.java:93:57:93:60 | code : String | ScriptEngineTest.java:20:44:20:55 | input : String |
|
||||
| ScriptEngineTest.java:94:64:94:67 | code : String | ScriptEngineTest.java:27:51:27:62 | input : String |
|
||||
| ScriptEngineTest.java:95:71:95:74 | code : String | ScriptEngineTest.java:35:58:35:69 | input : String |
|
||||
| ScriptEngineTest.java:96:59:96:62 | code : String | ScriptEngineTest.java:42:46:42:57 | input : String |
|
||||
| ScriptEngineTest.java:97:54:97:57 | code : String | ScriptEngineTest.java:49:41:49:52 | input : String |
|
||||
| ScriptEngineTest.java:98:54:98:57 | code : String | ScriptEngineTest.java:56:41:56:52 | input : String |
|
||||
nodes
|
||||
| RhinoServlet.java:28:23:28:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| RhinoServlet.java:32:55:32:58 | code | semmle.label | code |
|
||||
| RhinoServlet.java:81:23:81:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| RhinoServlet.java:83:54:83:57 | code | semmle.label | code |
|
||||
| RhinoServlet.java:88:23:88:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| RhinoServlet.java:89:74:89:88 | getBytes(...) | semmle.label | getBytes(...) |
|
||||
| ScriptEngineTest.java:20:44:20:55 | input : String | semmle.label | input : String |
|
||||
| ScriptEngineTest.java:24:37:24:41 | input | semmle.label | input |
|
||||
| ScriptEngineTest.java:27:51:27:62 | input : String | semmle.label | input : String |
|
||||
| ScriptEngineTest.java:31:31:31:35 | input | semmle.label | input |
|
||||
| ScriptEngineTest.java:35:58:35:69 | input : String | semmle.label | input : String |
|
||||
| ScriptEngineTest.java:39:31:39:35 | input | semmle.label | input |
|
||||
| ScriptEngineTest.java:42:46:42:57 | input : String | semmle.label | input : String |
|
||||
| ScriptEngineTest.java:46:31:46:35 | input | semmle.label | input |
|
||||
| ScriptEngineTest.java:49:41:49:52 | input : String | semmle.label | input : String |
|
||||
| ScriptEngineTest.java:52:42:52:46 | input | semmle.label | input |
|
||||
| ScriptEngineTest.java:56:41:56:52 | input : String | semmle.label | input : String |
|
||||
| ScriptEngineTest.java:59:51:59:55 | input | semmle.label | input |
|
||||
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| ScriptEngineTest.java:93:57:93:60 | code : String | semmle.label | code : String |
|
||||
| ScriptEngineTest.java:94:64:94:67 | code : String | semmle.label | code : String |
|
||||
| ScriptEngineTest.java:95:71:95:74 | code : String | semmle.label | code : String |
|
||||
| ScriptEngineTest.java:96:59:96:62 | code : String | semmle.label | code : String |
|
||||
| ScriptEngineTest.java:97:54:97:57 | code : String | semmle.label | code : String |
|
||||
| ScriptEngineTest.java:98:54:98:57 | code : String | semmle.label | code : String |
|
||||
#select
|
||||
| RhinoServlet.java:32:29:32:78 | evaluateString(...) | RhinoServlet.java:28:23:28:50 | getParameter(...) : String | RhinoServlet.java:32:55:32:58 | code | Java Script Engine evaluate $@. | RhinoServlet.java:28:23:28:50 | getParameter(...) | user input |
|
||||
| RhinoServlet.java:83:25:83:97 | compileToClassFiles(...) | RhinoServlet.java:81:23:81:50 | getParameter(...) : String | RhinoServlet.java:83:54:83:57 | code | Java Script Engine evaluate $@. | RhinoServlet.java:81:23:81:50 | getParameter(...) | user input |
|
||||
| RhinoServlet.java:89:23:89:89 | defineClass(...) | RhinoServlet.java:88:23:88:50 | getParameter(...) : String | RhinoServlet.java:89:74:89:88 | getBytes(...) | Java Script Engine evaluate $@. | RhinoServlet.java:88:23:88:50 | getParameter(...) | user input |
|
||||
| ScriptEngineTest.java:24:19:24:42 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:24:37:24:41 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
|
||||
| ScriptEngineTest.java:31:19:31:36 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:31:31:31:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
|
||||
| ScriptEngineTest.java:39:19:39:36 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:39:31:39:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
|
||||
| ScriptEngineTest.java:46:19:46:36 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:46:31:46:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
|
||||
| ScriptEngineTest.java:52:27:52:47 | compile(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:52:42:52:46 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
|
||||
| ScriptEngineTest.java:59:20:59:56 | getProgram(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:59:51:59:55 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-094/ScriptInjection.ql
|
||||
@@ -1,2 +1,2 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../stubs/groovy-all-3.0.7:${testdir}/../../../../stubs/servlet-api-2.4
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../stubs/groovy-all-3.0.7:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jython-2.7.2:${testdir}/../../../../experimental/stubs/rhino-1.7.13
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
edges
|
||||
| SpringUrlRedirect.java:13:30:13:47 | redirectUrl : String | SpringUrlRedirect.java:15:19:15:29 | redirectUrl |
|
||||
| SpringUrlRedirect.java:20:24:20:41 | redirectUrl : String | SpringUrlRedirect.java:21:36:21:46 | redirectUrl |
|
||||
| SpringUrlRedirect.java:26:30:26:47 | redirectUrl : String | SpringUrlRedirect.java:27:44:27:54 | redirectUrl |
|
||||
| SpringUrlRedirect.java:32:30:32:47 | redirectUrl : String | SpringUrlRedirect.java:33:47:33:57 | redirectUrl |
|
||||
| SpringUrlRedirect.java:37:24:37:41 | redirectUrl : String | SpringUrlRedirect.java:40:29:40:39 | redirectUrl |
|
||||
| SpringUrlRedirect.java:45:24:45:41 | redirectUrl : String | SpringUrlRedirect.java:48:30:48:40 | redirectUrl |
|
||||
| SpringUrlRedirect.java:53:24:53:41 | redirectUrl : String | SpringUrlRedirect.java:54:30:54:66 | format(...) |
|
||||
| SpringUrlRedirect.java:58:24:58:41 | redirectUrl : String | SpringUrlRedirect.java:59:30:59:76 | format(...) |
|
||||
nodes
|
||||
| SpringUrlRedirect.java:13:30:13:47 | redirectUrl : String | semmle.label | redirectUrl : String |
|
||||
| SpringUrlRedirect.java:15:19:15:29 | redirectUrl | semmle.label | redirectUrl |
|
||||
| SpringUrlRedirect.java:20:24:20:41 | redirectUrl : String | semmle.label | redirectUrl : String |
|
||||
| SpringUrlRedirect.java:21:36:21:46 | redirectUrl | semmle.label | redirectUrl |
|
||||
| SpringUrlRedirect.java:26:30:26:47 | redirectUrl : String | semmle.label | redirectUrl : String |
|
||||
| SpringUrlRedirect.java:27:44:27:54 | redirectUrl | semmle.label | redirectUrl |
|
||||
| SpringUrlRedirect.java:32:30:32:47 | redirectUrl : String | semmle.label | redirectUrl : String |
|
||||
| SpringUrlRedirect.java:33:47:33:57 | redirectUrl | semmle.label | redirectUrl |
|
||||
| SpringUrlRedirect.java:37:24:37:41 | redirectUrl : String | semmle.label | redirectUrl : String |
|
||||
| SpringUrlRedirect.java:40:29:40:39 | redirectUrl | semmle.label | redirectUrl |
|
||||
| SpringUrlRedirect.java:45:24:45:41 | redirectUrl : String | semmle.label | redirectUrl : String |
|
||||
| SpringUrlRedirect.java:48:30:48:40 | redirectUrl | semmle.label | redirectUrl |
|
||||
| SpringUrlRedirect.java:53:24:53:41 | redirectUrl : String | semmle.label | redirectUrl : String |
|
||||
| SpringUrlRedirect.java:54:30:54:66 | format(...) | semmle.label | format(...) |
|
||||
| SpringUrlRedirect.java:58:24:58:41 | redirectUrl : String | semmle.label | redirectUrl : String |
|
||||
| SpringUrlRedirect.java:59:30:59:76 | format(...) | semmle.label | format(...) |
|
||||
#select
|
||||
| SpringUrlRedirect.java:15:19:15:29 | redirectUrl | SpringUrlRedirect.java:13:30:13:47 | redirectUrl : String | SpringUrlRedirect.java:15:19:15:29 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:13:30:13:47 | redirectUrl | user-provided value |
|
||||
| SpringUrlRedirect.java:21:36:21:46 | redirectUrl | SpringUrlRedirect.java:20:24:20:41 | redirectUrl : String | SpringUrlRedirect.java:21:36:21:46 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:20:24:20:41 | redirectUrl | user-provided value |
|
||||
| SpringUrlRedirect.java:27:44:27:54 | redirectUrl | SpringUrlRedirect.java:26:30:26:47 | redirectUrl : String | SpringUrlRedirect.java:27:44:27:54 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:26:30:26:47 | redirectUrl | user-provided value |
|
||||
| SpringUrlRedirect.java:33:47:33:57 | redirectUrl | SpringUrlRedirect.java:32:30:32:47 | redirectUrl : String | SpringUrlRedirect.java:33:47:33:57 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:32:30:32:47 | redirectUrl | user-provided value |
|
||||
| SpringUrlRedirect.java:40:29:40:39 | redirectUrl | SpringUrlRedirect.java:37:24:37:41 | redirectUrl : String | SpringUrlRedirect.java:40:29:40:39 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:37:24:37:41 | redirectUrl | user-provided value |
|
||||
| SpringUrlRedirect.java:48:30:48:40 | redirectUrl | SpringUrlRedirect.java:45:24:45:41 | redirectUrl : String | SpringUrlRedirect.java:48:30:48:40 | redirectUrl | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:45:24:45:41 | redirectUrl | user-provided value |
|
||||
| SpringUrlRedirect.java:54:30:54:66 | format(...) | SpringUrlRedirect.java:53:24:53:41 | redirectUrl : String | SpringUrlRedirect.java:54:30:54:66 | format(...) | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:53:24:53:41 | redirectUrl | user-provided value |
|
||||
| SpringUrlRedirect.java:59:30:59:76 | format(...) | SpringUrlRedirect.java:58:24:58:41 | redirectUrl : String | SpringUrlRedirect.java:59:30:59:76 | format(...) | Potentially untrusted URL redirection due to $@. | SpringUrlRedirect.java:58:24:58:41 | redirectUrl | user-provided value |
|
||||
@@ -0,0 +1,83 @@
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
@Controller
|
||||
public class SpringUrlRedirect {
|
||||
|
||||
private final static String VALID_REDIRECT = "http://127.0.0.1";
|
||||
|
||||
@GetMapping("url1")
|
||||
public RedirectView bad1(String redirectUrl, HttpServletResponse response) throws Exception {
|
||||
RedirectView rv = new RedirectView();
|
||||
rv.setUrl(redirectUrl);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@GetMapping("url2")
|
||||
public String bad2(String redirectUrl) {
|
||||
String url = "redirect:" + redirectUrl;
|
||||
return url;
|
||||
}
|
||||
|
||||
@GetMapping("url3")
|
||||
public RedirectView bad3(String redirectUrl) {
|
||||
RedirectView rv = new RedirectView(redirectUrl);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@GetMapping("url4")
|
||||
public ModelAndView bad4(String redirectUrl) {
|
||||
return new ModelAndView("redirect:" + redirectUrl);
|
||||
}
|
||||
|
||||
@GetMapping("url5")
|
||||
public String bad5(String redirectUrl) {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
stringBuffer.append("redirect:");
|
||||
stringBuffer.append(redirectUrl);
|
||||
return stringBuffer.toString();
|
||||
}
|
||||
|
||||
@GetMapping("url6")
|
||||
public String bad6(String redirectUrl) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append("redirect:");
|
||||
stringBuilder.append(redirectUrl);
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
@GetMapping("url7")
|
||||
public String bad7(String redirectUrl) {
|
||||
return "redirect:" + String.format("%s/?aaa", redirectUrl);
|
||||
}
|
||||
|
||||
@GetMapping("url8")
|
||||
public String bad8(String redirectUrl, String token) {
|
||||
return "redirect:" + String.format(redirectUrl + "?token=%s", token);
|
||||
}
|
||||
|
||||
@GetMapping("url9")
|
||||
public RedirectView good1(String redirectUrl) {
|
||||
RedirectView rv = new RedirectView();
|
||||
if (redirectUrl.startsWith(VALID_REDIRECT)){
|
||||
rv.setUrl(redirectUrl);
|
||||
}else {
|
||||
rv.setUrl(VALID_REDIRECT);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@GetMapping("url10")
|
||||
public ModelAndView good2(String token) {
|
||||
String url = "/edit?token=" + token;
|
||||
return new ModelAndView("redirect:" + url);
|
||||
}
|
||||
|
||||
@GetMapping("url11")
|
||||
public String good3(String status) {
|
||||
return "redirect:" + String.format("/stories/search/criteria?status=%s", status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-601/SpringUrlRedirect.ql
|
||||
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.2.3/
|
||||
@@ -0,0 +1,56 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
Embeddings that wish to filter Java classes that are visible to scripts
|
||||
through the LiveConnect, should implement this interface.
|
||||
|
||||
@see Context#setClassShutter(ClassShutter)
|
||||
@since 1.5 Release 4
|
||||
@author Norris Boyd
|
||||
*/
|
||||
|
||||
public interface ClassShutter {
|
||||
|
||||
/**
|
||||
* Return true iff the Java class with the given name should be exposed
|
||||
* to scripts.
|
||||
* <p>
|
||||
* An embedding may filter which Java classes are exposed through
|
||||
* LiveConnect to JavaScript scripts.
|
||||
* <p>
|
||||
* Due to the fact that there is no package reflection in Java,
|
||||
* this method will also be called with package names. There
|
||||
* is no way for Rhino to tell if "Packages.a.b" is a package name
|
||||
* or a class that doesn't exist. What Rhino does is attempt
|
||||
* to load each segment of "Packages.a.b.c": It first attempts to
|
||||
* load class "a", then attempts to load class "a.b", then
|
||||
* finally attempts to load class "a.b.c". On a Rhino installation
|
||||
* without any ClassShutter set, and without any of the
|
||||
* above classes, the expression "Packages.a.b.c" will result in
|
||||
* a [JavaPackage a.b.c] and not an error.
|
||||
* <p>
|
||||
* With ClassShutter supplied, Rhino will first call
|
||||
* visibleToScripts before attempting to look up the class name. If
|
||||
* visibleToScripts returns false, the class name lookup is not
|
||||
* performed and subsequent Rhino execution assumes the class is
|
||||
* not present. So for "java.lang.System.out.println" the lookup
|
||||
* of "java.lang.System" is skipped and thus Rhino assumes that
|
||||
* "java.lang.System" doesn't exist. So then for "java.lang.System.out",
|
||||
* Rhino attempts to load the class "java.lang.System.out" because
|
||||
* it assumes that "java.lang.System" is a package name.
|
||||
* <p>
|
||||
* @param fullClassName the full name of the class (including the package
|
||||
* name, with '.' as a delimiter). For example the
|
||||
* standard string class is "java.lang.String"
|
||||
* @return whether or not to reveal this class to scripts
|
||||
*/
|
||||
public boolean visibleToScripts(String fullClassName);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
public class CompilerEnvirons {
|
||||
public CompilerEnvirons() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,695 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* This class represents the runtime context of an executing script.
|
||||
*
|
||||
* Before executing a script, an instance of Context must be created
|
||||
* and associated with the thread that will be executing the script.
|
||||
* The Context will be used to store information about the executing
|
||||
* of the script such as the call stack. Contexts are associated with
|
||||
* the current thread using the {@link #call(ContextAction)}
|
||||
* or {@link #enter()} methods.<p>
|
||||
*
|
||||
* Different forms of script execution are supported. Scripts may be
|
||||
* evaluated from the source directly, or first compiled and then later
|
||||
* executed. Interactive execution is also supported.<p>
|
||||
*
|
||||
* Some aspects of script execution, such as type conversions and
|
||||
* object creation, may be accessed directly through methods of
|
||||
* Context.
|
||||
*
|
||||
* @see Scriptable
|
||||
* @author Norris Boyd
|
||||
* @author Brendan Eich
|
||||
*/
|
||||
|
||||
public class Context
|
||||
implements Closeable
|
||||
{
|
||||
/**
|
||||
* Creates a new Context. The context will be associated with the {@link
|
||||
* ContextFactory#getGlobal() global context factory}.
|
||||
*
|
||||
* Note that the Context must be associated with a thread before
|
||||
* it can be used to execute a script.
|
||||
* @deprecated this constructor is deprecated because it creates a
|
||||
* dependency on a static singleton context factory. Use
|
||||
* {@link ContextFactory#enter()} or
|
||||
* {@link ContextFactory#call(ContextAction)} instead. If you subclass
|
||||
* this class, consider using {@link #Context(ContextFactory)} constructor
|
||||
* instead in the subclasses' constructors.
|
||||
*/
|
||||
@Deprecated
|
||||
public Context()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new context. Provided as a preferred super constructor for
|
||||
* subclasses in place of the deprecated default public constructor.
|
||||
* @param factory the context factory associated with this context (most
|
||||
* likely, the one that created the context). Can not be null. The context
|
||||
* features are inherited from the factory, and the context will also
|
||||
* otherwise use its factory's services.
|
||||
* @throws IllegalArgumentException if factory parameter is null.
|
||||
*/
|
||||
protected Context(ContextFactory factory)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current Context.
|
||||
*
|
||||
* The current Context is per-thread; this method looks up
|
||||
* the Context associated with the current thread. <p>
|
||||
*
|
||||
* @return the Context associated with the current thread, or
|
||||
* null if no context is associated with the current
|
||||
* thread.
|
||||
* @see ContextFactory#enterContext()
|
||||
* @see ContextFactory#call(ContextAction)
|
||||
*/
|
||||
public static Context getCurrentContext()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as calling {@link ContextFactory#enterContext()} on the global
|
||||
* ContextFactory instance.
|
||||
* @return a Context associated with the current thread
|
||||
* @see #getCurrentContext()
|
||||
* @see #exit()
|
||||
* @see #call(ContextAction)
|
||||
*/
|
||||
public static Context enter()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Context associated with the current thread, using
|
||||
* the given Context if need be.
|
||||
* <p>
|
||||
* The same as <code>enter()</code> except that <code>cx</code>
|
||||
* is associated with the current thread and returned if
|
||||
* the current thread has no associated context and <code>cx</code>
|
||||
* is not associated with any other thread.
|
||||
* @param cx a Context to associate with the thread if possible
|
||||
* @return a Context associated with the current thread
|
||||
* @deprecated use {@link ContextFactory#enterContext(Context)} instead as
|
||||
* this method relies on usage of a static singleton "global" ContextFactory.
|
||||
* @see ContextFactory#enterContext(Context)
|
||||
* @see ContextFactory#call(ContextAction)
|
||||
*/
|
||||
@Deprecated
|
||||
public static Context enter(Context cx)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
static final Context enter(Context cx, ContextFactory factory)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit a block of code requiring a Context.
|
||||
*
|
||||
* Calling <code>exit()</code> will remove the association between
|
||||
* the current thread and a Context if the prior call to
|
||||
* {@link ContextFactory#enterContext()} on this thread newly associated a
|
||||
* Context with this thread. Once the current thread no longer has an
|
||||
* associated Context, it cannot be used to execute JavaScript until it is
|
||||
* again associated with a Context.
|
||||
* @see ContextFactory#enterContext()
|
||||
*/
|
||||
public static void exit()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link ContextFactory} instance used to create this Context.
|
||||
*/
|
||||
public final ContextFactory getFactory()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this is a sealed Context. A sealed Context instance does not
|
||||
* allow to modify any of its properties and will throw an exception
|
||||
* on any such attempt.
|
||||
* @see #seal(Object sealKey)
|
||||
*/
|
||||
public final boolean isSealed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seal this Context object so any attempt to modify any of its properties
|
||||
* including calling {@link #enter()} and {@link #exit()} methods will
|
||||
* throw an exception.
|
||||
* <p>
|
||||
* If <code>sealKey</code> is not null, calling
|
||||
* {@link #unseal(Object sealKey)} with the same key unseals
|
||||
* the object. If <code>sealKey</code> is null, unsealing is no longer possible.
|
||||
*
|
||||
* @see #isSealed()
|
||||
* @see #unseal(Object)
|
||||
*/
|
||||
public final void seal(Object sealKey)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Unseal previously sealed Context object.
|
||||
* The <code>sealKey</code> argument should not be null and should match
|
||||
* <code>sealKey</code> suplied with the last call to
|
||||
* {@link #seal(Object)} or an exception will be thrown.
|
||||
*
|
||||
* @see #isSealed()
|
||||
* @see #seal(Object sealKey)
|
||||
*/
|
||||
public final void unseal(Object sealKey)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current language version.
|
||||
* <p>
|
||||
* The language version number affects JavaScript semantics as detailed
|
||||
* in the overview documentation.
|
||||
*
|
||||
* @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.
|
||||
*/
|
||||
public final int getLanguageVersion()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the language version.
|
||||
*
|
||||
* <p>
|
||||
* Setting the language version will affect functions and scripts compiled
|
||||
* subsequently. See the overview documentation for version-specific
|
||||
* behavior.
|
||||
*
|
||||
* @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.
|
||||
*/
|
||||
public void setLanguageVersion(int version)
|
||||
{
|
||||
}
|
||||
|
||||
public static boolean isValidLanguageVersion(int version)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void checkLanguageVersion(int version)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the implementation version.
|
||||
*
|
||||
* <p>
|
||||
* The implementation version is of the form
|
||||
* <pre>
|
||||
* "<i>name langVer</i> <code>release</code> <i>relNum date</i>"
|
||||
* </pre>
|
||||
* where <i>name</i> is the name of the product, <i>langVer</i> is
|
||||
* the language version, <i>relNum</i> is the release number, and
|
||||
* <i>date</i> is the release date for that specific
|
||||
* release in the form "yyyy mm dd".
|
||||
*
|
||||
* @return a string that encodes the product, language version, release
|
||||
* number, and date.
|
||||
*/
|
||||
public final String getImplementationVersion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the standard objects.
|
||||
*
|
||||
* Creates instances of the standard objects and their constructors
|
||||
* (Object, String, Number, Date, etc.), setting up 'scope' to act
|
||||
* as a global object as in ECMA 15.1.<p>
|
||||
*
|
||||
* This method must be called to initialize a scope before scripts
|
||||
* can be evaluated in that scope.<p>
|
||||
*
|
||||
* This method does not affect the Context it is called upon.
|
||||
*
|
||||
* @return the initialized scope
|
||||
*/
|
||||
public final ScriptableObject initStandardObjects()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the standard objects, leaving out those that offer access directly
|
||||
* to Java classes. This sets up "scope" to have access to all the standard
|
||||
* JavaScript classes, but does not create global objects for any top-level
|
||||
* Java packages. In addition, the "Packages," "JavaAdapter," and
|
||||
* "JavaImporter" classes, and the "getClass" function, are not
|
||||
* initialized.
|
||||
*
|
||||
* The result of this function is a scope that may be safely used in a "sandbox"
|
||||
* environment where it is not desirable to give access to Java code from JavaScript.
|
||||
*
|
||||
* Creates instances of the standard objects and their constructors
|
||||
* (Object, String, Number, Date, etc.), setting up 'scope' to act
|
||||
* as a global object as in ECMA 15.1.<p>
|
||||
*
|
||||
* This method must be called to initialize a scope before scripts
|
||||
* can be evaluated in that scope.<p>
|
||||
*
|
||||
* This method does not affect the Context it is called upon.
|
||||
*
|
||||
* @return the initialized scope
|
||||
*/
|
||||
public final ScriptableObject initSafeStandardObjects()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the standard objects.
|
||||
*
|
||||
* Creates instances of the standard objects and their constructors
|
||||
* (Object, String, Number, Date, etc.), setting up 'scope' to act
|
||||
* as a global object as in ECMA 15.1.<p>
|
||||
*
|
||||
* This method must be called to initialize a scope before scripts
|
||||
* can be evaluated in that scope.<p>
|
||||
*
|
||||
* This method does not affect the Context it is called upon.
|
||||
*
|
||||
* @param scope the scope to initialize, or null, in which case a new
|
||||
* object will be created to serve as the scope
|
||||
* @return the initialized scope. The method returns the value of the scope
|
||||
* argument if it is not null or newly allocated scope object which
|
||||
* is an instance {@link ScriptableObject}.
|
||||
*/
|
||||
public final Scriptable initStandardObjects(ScriptableObject scope)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the standard objects, leaving out those that offer access directly
|
||||
* to Java classes. This sets up "scope" to have access to all the standard
|
||||
* JavaScript classes, but does not create global objects for any top-level
|
||||
* Java packages. In addition, the "Packages," "JavaAdapter," and
|
||||
* "JavaImporter" classes, and the "getClass" function, are not
|
||||
* initialized.
|
||||
*
|
||||
* The result of this function is a scope that may be safely used in a "sandbox"
|
||||
* environment where it is not desirable to give access to Java code from JavaScript.
|
||||
*
|
||||
* Creates instances of the standard objects and their constructors
|
||||
* (Object, String, Number, Date, etc.), setting up 'scope' to act
|
||||
* as a global object as in ECMA 15.1.<p>
|
||||
*
|
||||
* This method must be called to initialize a scope before scripts
|
||||
* can be evaluated in that scope.<p>
|
||||
*
|
||||
* This method does not affect the Context it is called upon.
|
||||
*
|
||||
* @param scope the scope to initialize, or null, in which case a new
|
||||
* object will be created to serve as the scope
|
||||
* @return the initialized scope. The method returns the value of the scope
|
||||
* argument if it is not null or newly allocated scope object which
|
||||
* is an instance {@link ScriptableObject}.
|
||||
*/
|
||||
public final Scriptable initSafeStandardObjects(ScriptableObject scope)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the standard objects.
|
||||
*
|
||||
* Creates instances of the standard objects and their constructors
|
||||
* (Object, String, Number, Date, etc.), setting up 'scope' to act
|
||||
* as a global object as in ECMA 15.1.<p>
|
||||
*
|
||||
* This method must be called to initialize a scope before scripts
|
||||
* can be evaluated in that scope.<p>
|
||||
*
|
||||
* This method does not affect the Context it is called upon.<p>
|
||||
*
|
||||
* This form of the method also allows for creating "sealed" standard
|
||||
* objects. An object that is sealed cannot have properties added, changed,
|
||||
* or removed. This is useful to create a "superglobal" that can be shared
|
||||
* among several top-level objects. Note that sealing is not allowed in
|
||||
* the current ECMA/ISO language specification, but is likely for
|
||||
* the next version.
|
||||
*
|
||||
* @param scope the scope to initialize, or null, in which case a new
|
||||
* object will be created to serve as the scope
|
||||
* @param sealed whether or not to create sealed standard objects that
|
||||
* cannot be modified.
|
||||
* @return the initialized scope. The method returns the value of the scope
|
||||
* argument if it is not null or newly allocated scope object.
|
||||
* @since 1.4R3
|
||||
*/
|
||||
public ScriptableObject initStandardObjects(ScriptableObject scope,
|
||||
boolean sealed)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the standard objects, leaving out those that offer access directly
|
||||
* to Java classes. This sets up "scope" to have access to all the standard
|
||||
* JavaScript classes, but does not create global objects for any top-level
|
||||
* Java packages. In addition, the "Packages," "JavaAdapter," and
|
||||
* "JavaImporter" classes, and the "getClass" function, are not
|
||||
* initialized.
|
||||
*
|
||||
* The result of this function is a scope that may be safely used in a "sandbox"
|
||||
* environment where it is not desirable to give access to Java code from JavaScript.
|
||||
*
|
||||
* Creates instances of the standard objects and their constructors
|
||||
* (Object, String, Number, Date, etc.), setting up 'scope' to act
|
||||
* as a global object as in ECMA 15.1.<p>
|
||||
*
|
||||
* This method must be called to initialize a scope before scripts
|
||||
* can be evaluated in that scope.<p>
|
||||
*
|
||||
* This method does not affect the Context it is called upon.<p>
|
||||
*
|
||||
* This form of the method also allows for creating "sealed" standard
|
||||
* objects. An object that is sealed cannot have properties added, changed,
|
||||
* or removed. This is useful to create a "superglobal" that can be shared
|
||||
* among several top-level objects. Note that sealing is not allowed in
|
||||
* the current ECMA/ISO language specification, but is likely for
|
||||
* the next version.
|
||||
*
|
||||
* @param scope the scope to initialize, or null, in which case a new
|
||||
* object will be created to serve as the scope
|
||||
* @param sealed whether or not to create sealed standard objects that
|
||||
* cannot be modified.
|
||||
* @return the initialized scope. The method returns the value of the scope
|
||||
* argument if it is not null or newly allocated scope object.
|
||||
* @since 1.7.6
|
||||
*/
|
||||
public ScriptableObject initSafeStandardObjects(ScriptableObject scope,
|
||||
boolean sealed)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton object that represents the JavaScript Undefined value.
|
||||
*/
|
||||
public static Object getUndefinedValue()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate a JavaScript source string.
|
||||
*
|
||||
* The provided source name and line number are used for error messages
|
||||
* and for producing debug information.
|
||||
*
|
||||
* @param scope the scope to execute in
|
||||
* @param source the JavaScript source
|
||||
* @param sourceName a string describing the source, such as a filename
|
||||
* @param lineno the starting line number
|
||||
* @param securityDomain an arbitrary object that specifies security
|
||||
* information about the origin or owner of the script. For
|
||||
* implementations that don't care about security, this value
|
||||
* may be null.
|
||||
* @return the result of evaluating the string
|
||||
* @see org.mozilla.javascript.SecurityController
|
||||
*/
|
||||
public final Object evaluateString(Scriptable scope, String source,
|
||||
String sourceName, int lineno,
|
||||
Object securityDomain)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate a reader as JavaScript source.
|
||||
*
|
||||
* All characters of the reader are consumed.
|
||||
*
|
||||
* @param scope the scope to execute in
|
||||
* @param in the Reader to get JavaScript source from
|
||||
* @param sourceName a string describing the source, such as a filename
|
||||
* @param lineno the starting line number
|
||||
* @param securityDomain an arbitrary object that specifies security
|
||||
* information about the origin or owner of the script. For
|
||||
* implementations that don't care about security, this value
|
||||
* may be null.
|
||||
* @return the result of evaluating the source
|
||||
*
|
||||
* @exception IOException if an IOException was generated by the Reader
|
||||
*/
|
||||
public final Object evaluateReader(Scriptable scope, Reader in,
|
||||
String sourceName, int lineno,
|
||||
Object securityDomain)
|
||||
throws IOException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see #compileReader(Reader in, String sourceName, int lineno, Object securityDomain)
|
||||
*/
|
||||
@Deprecated
|
||||
public final Script compileReader(
|
||||
Scriptable scope, Reader in, String sourceName, int lineno, Object securityDomain)
|
||||
throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the source in the given reader.
|
||||
*
|
||||
* <p>Returns a script that may later be executed. Will consume all the source in the reader.
|
||||
*
|
||||
* @param in the input reader
|
||||
* @param sourceName a string describing the source, such as a filename
|
||||
* @param lineno the starting line number for reporting errors
|
||||
* @param securityDomain an arbitrary object that specifies security information about the
|
||||
* origin or owner of the script. For implementations that don't care about security, this
|
||||
* value may be null.
|
||||
* @return a script that may later be executed
|
||||
* @exception IOException if an IOException was generated by the Reader
|
||||
* @see org.mozilla.javascript.Script
|
||||
*/
|
||||
public final Script compileReader(
|
||||
Reader in, String sourceName, int lineno, Object securityDomain) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the source in the given string.
|
||||
*
|
||||
* <p>Returns a script that may later be executed.
|
||||
*
|
||||
* @param source the source string
|
||||
* @param sourceName a string describing the source, such as a filename
|
||||
* @param lineno the starting line number for reporting errors. Use 0 if the line number is
|
||||
* unknown.
|
||||
* @param securityDomain an arbitrary object that specifies security information about the
|
||||
* origin or owner of the script. For implementations that don't care about security, this
|
||||
* value may be null.
|
||||
* @return a script that may later be executed
|
||||
* @see org.mozilla.javascript.Script
|
||||
*/
|
||||
public final Script compileString(
|
||||
String source, String sourceName, int lineno, Object securityDomain) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a JavaScript function.
|
||||
*
|
||||
* <p>The function source must be a function definition as defined by ECMA (e.g., "function f(a)
|
||||
* { return a; }").
|
||||
*
|
||||
* @param scope the scope to compile relative to
|
||||
* @param source the function definition source
|
||||
* @param sourceName a string describing the source, such as a filename
|
||||
* @param lineno the starting line number
|
||||
* @param securityDomain an arbitrary object that specifies security information about the
|
||||
* origin or owner of the script. For implementations that don't care about security, this
|
||||
* value may be null.
|
||||
* @return a Function that may later be called
|
||||
* @see org.mozilla.javascript.Function
|
||||
*/
|
||||
public final Function compileFunction(
|
||||
Scriptable scope, String source, String sourceName, int lineno, Object securityDomain) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a JavaScript boolean value.
|
||||
* <p>
|
||||
* See ECMA 9.2.
|
||||
*
|
||||
* @param value a JavaScript value
|
||||
* @return the corresponding boolean value converted using
|
||||
* the ECMA rules
|
||||
*/
|
||||
public static boolean toBoolean(Object value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a JavaScript Number value.
|
||||
* <p>
|
||||
* Returns a Java double for the JavaScript Number.
|
||||
* <p>
|
||||
* See ECMA 9.3.
|
||||
*
|
||||
* @param value a JavaScript value
|
||||
* @return the corresponding double value converted using
|
||||
* the ECMA rules
|
||||
*/
|
||||
public static double toNumber(Object value)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a JavaScript String value.
|
||||
* <p>
|
||||
* See ECMA 9.8.
|
||||
* <p>
|
||||
* @param value a JavaScript value
|
||||
* @return the corresponding String value converted using
|
||||
* the ECMA rules
|
||||
*/
|
||||
public static String toString(Object value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to an JavaScript object value.
|
||||
* <p>
|
||||
* Note that a scope must be provided to look up the constructors
|
||||
* for Number, Boolean, and String.
|
||||
* <p>
|
||||
* See ECMA 9.9.
|
||||
* <p>
|
||||
* Additionally, arbitrary Java objects and classes will be
|
||||
* wrapped in a Scriptable object with its Java fields and methods
|
||||
* reflected as JavaScript properties of the object.
|
||||
*
|
||||
* @param value any Java object
|
||||
* @param scope global scope containing constructors for Number,
|
||||
* Boolean, and String
|
||||
* @return new JavaScript object
|
||||
*/
|
||||
public static Scriptable toObject(Object value, Scriptable scope)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method to convert java value to its closest representation
|
||||
* in JavaScript.
|
||||
* <p>
|
||||
* If value is an instance of String, Number, Boolean, Function or
|
||||
* Scriptable, it is returned as it and will be treated as the corresponding
|
||||
* JavaScript type of string, number, boolean, function and object.
|
||||
* <p>
|
||||
* Note that for Number instances during any arithmetic operation in
|
||||
* JavaScript the engine will always use the result of
|
||||
* <code>Number.doubleValue()</code> resulting in a precision loss if
|
||||
* the number can not fit into double.
|
||||
* <p>
|
||||
* If value is an instance of Character, it will be converted to string of
|
||||
* length 1 and its JavaScript type will be string.
|
||||
* <p>
|
||||
* The rest of values will be wrapped as LiveConnect objects
|
||||
* by calling {@link WrapFactory#wrap(Context cx, Scriptable scope,
|
||||
* Object obj, Class staticType)} as in:
|
||||
* <pre>
|
||||
* Context cx = Context.getCurrentContext();
|
||||
* return cx.getWrapFactory().wrap(cx, scope, value, null);
|
||||
* </pre>
|
||||
*
|
||||
* @param value any Java object
|
||||
* @param scope top scope object
|
||||
* @return value suitable to pass to any API that takes JavaScript values.
|
||||
*/
|
||||
public static Object javaToJS(Object value, Scriptable scope)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a JavaScript value into the desired type.
|
||||
* Uses the semantics defined with LiveConnect3 and throws an
|
||||
* Illegal argument exception if the conversion cannot be performed.
|
||||
* @param value the JavaScript value to convert
|
||||
* @param desiredType the Java type to convert to. Primitive Java
|
||||
* types are represented using the TYPE fields in the corresponding
|
||||
* wrapper class in java.lang.
|
||||
* @return the converted value
|
||||
* @throws EvaluatorException if the conversion cannot be performed
|
||||
*/
|
||||
public static Object jsToJava(Object value, Class<?> desiredType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the LiveConnect access filter for this context.
|
||||
* <p> {@link ClassShutter} may only be set if it is currently null.
|
||||
* Otherwise a SecurityException is thrown.
|
||||
* @param shutter a ClassShutter object
|
||||
* @throws SecurityException if there is already a ClassShutter
|
||||
* object for this Context
|
||||
*/
|
||||
public synchronized final void setClassShutter(ClassShutter shutter)
|
||||
{
|
||||
}
|
||||
|
||||
final synchronized ClassShutter getClassShutter()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public interface ClassShutterSetter {
|
||||
public void setClassShutter(ClassShutter shutter);
|
||||
public ClassShutter getClassShutter();
|
||||
}
|
||||
|
||||
public final synchronized ClassShutterSetter getClassShutterSetter() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* Factory class that Rhino runtime uses to create new {@link Context}
|
||||
* instances. A <code>ContextFactory</code> can also notify listeners
|
||||
* about context creation and release.
|
||||
* <p>
|
||||
* When the Rhino runtime needs to create new {@link Context} instance during
|
||||
* execution of {@link Context#enter()} or {@link Context}, it will call
|
||||
* {@link #makeContext()} of the current global ContextFactory.
|
||||
* See {@link #getGlobal()} and {@link #initGlobal(ContextFactory)}.
|
||||
* <p>
|
||||
* It is also possible to use explicit ContextFactory instances for Context
|
||||
* creation. This is useful to have a set of independent Rhino runtime
|
||||
* instances under single JVM. See {@link #call(ContextAction)}.
|
||||
* <p>
|
||||
* The following example demonstrates Context customization to terminate
|
||||
* scripts running more then 10 seconds and to provide better compatibility
|
||||
* with JavaScript code using MSIE-specific features.
|
||||
* <pre>
|
||||
* import org.mozilla.javascript.*;
|
||||
*
|
||||
* class MyFactory extends ContextFactory
|
||||
* {
|
||||
*
|
||||
* // Custom {@link Context} to store execution time.
|
||||
* private static class MyContext extends Context
|
||||
* {
|
||||
* long startTime;
|
||||
* }
|
||||
*
|
||||
* static {
|
||||
* // Initialize GlobalFactory with custom factory
|
||||
* ContextFactory.initGlobal(new MyFactory());
|
||||
* }
|
||||
*
|
||||
* // Override {@link #makeContext()}
|
||||
* protected Context makeContext()
|
||||
* {
|
||||
* MyContext cx = new MyContext();
|
||||
* // Make Rhino runtime to call observeInstructionCount
|
||||
* // each 10000 bytecode instructions
|
||||
* cx.setInstructionObserverThreshold(10000);
|
||||
* return cx;
|
||||
* }
|
||||
*
|
||||
* // Override {@link #hasFeature(Context, int)}
|
||||
* public boolean hasFeature(Context cx, int featureIndex)
|
||||
* {
|
||||
* // Turn on maximum compatibility with MSIE scripts
|
||||
* switch (featureIndex) {
|
||||
* case {@link Context#FEATURE_NON_ECMA_GET_YEAR}:
|
||||
* return true;
|
||||
*
|
||||
* case {@link Context#FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME}:
|
||||
* return true;
|
||||
*
|
||||
* case {@link Context#FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER}:
|
||||
* return true;
|
||||
*
|
||||
* case {@link Context#FEATURE_PARENT_PROTO_PROPERTIES}:
|
||||
* return false;
|
||||
* }
|
||||
* return super.hasFeature(cx, featureIndex);
|
||||
* }
|
||||
*
|
||||
* // Override {@link #observeInstructionCount(Context, int)}
|
||||
* protected void observeInstructionCount(Context cx, int instructionCount)
|
||||
* {
|
||||
* MyContext mcx = (MyContext)cx;
|
||||
* long currentTime = System.currentTimeMillis();
|
||||
* if (currentTime - mcx.startTime > 10*1000) {
|
||||
* // More then 10 seconds from Context creation time:
|
||||
* // it is time to stop the script.
|
||||
* // Throw Error instance to ensure that script will never
|
||||
* // get control back through catch or finally.
|
||||
* throw new Error();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // Override {@link #doTopCall(Callable,
|
||||
Context, Scriptable,
|
||||
Scriptable, Object[])}
|
||||
* protected Object doTopCall(Callable callable,
|
||||
* Context cx, Scriptable scope,
|
||||
* Scriptable thisObj, Object[] args)
|
||||
* {
|
||||
* MyContext mcx = (MyContext)cx;
|
||||
* mcx.startTime = System.currentTimeMillis();
|
||||
*
|
||||
* return super.doTopCall(callable, cx, scope, thisObj, args);
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
public class ContextFactory
|
||||
{
|
||||
|
||||
/**
|
||||
* Listener of {@link Context} creation and release events.
|
||||
*/
|
||||
public interface Listener
|
||||
{
|
||||
/**
|
||||
* Notify about newly created {@link Context} object.
|
||||
*/
|
||||
public void contextCreated(Context cx);
|
||||
|
||||
/**
|
||||
* Notify that the specified {@link Context} instance is no longer
|
||||
* associated with the current thread.
|
||||
*/
|
||||
public void contextReleased(Context cx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get global ContextFactory.
|
||||
*
|
||||
* @see #hasExplicitGlobal()
|
||||
* @see #initGlobal(ContextFactory)
|
||||
*/
|
||||
public static ContextFactory getGlobal()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if global factory was set.
|
||||
* Return true to indicate that {@link #initGlobal(ContextFactory)} was
|
||||
* already called and false to indicate that the global factory was not
|
||||
* explicitly set.
|
||||
*
|
||||
* @see #getGlobal()
|
||||
* @see #initGlobal(ContextFactory)
|
||||
*/
|
||||
public static boolean hasExplicitGlobal()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set global ContextFactory.
|
||||
* The method can only be called once.
|
||||
*
|
||||
* @see #getGlobal()
|
||||
* @see #hasExplicitGlobal()
|
||||
*/
|
||||
public synchronized static void initGlobal(ContextFactory factory)
|
||||
{
|
||||
}
|
||||
|
||||
public interface GlobalSetter {
|
||||
public void setContextFactoryGlobal(ContextFactory factory);
|
||||
public ContextFactory getContextFactoryGlobal();
|
||||
}
|
||||
|
||||
public synchronized static GlobalSetter getGlobalSetter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link Context} instance to be associated with the current
|
||||
* thread.
|
||||
* This is a callback method used by Rhino to create {@link Context}
|
||||
* instance when it is necessary to associate one with the current
|
||||
* execution thread. <code>makeContext()</code> is allowed to call
|
||||
* {@link Context#seal(Object)} on the result to prevent
|
||||
* {@link Context} changes by hostile scripts or applets.
|
||||
*/
|
||||
protected Context makeContext()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of {@link Context#hasFeature(int featureIndex)}.
|
||||
* This can be used to customize {@link Context} without introducing
|
||||
* additional subclasses.
|
||||
*/
|
||||
protected boolean hasFeature(Context cx, int featureIndex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ClassLoader to use when searching for Java classes.
|
||||
* Unless it was explicitly initialized with
|
||||
* {@link #initApplicationClassLoader(ClassLoader)} the method returns
|
||||
* null to indicate that Thread.getContextClassLoader() should be used.
|
||||
*/
|
||||
public final ClassLoader getApplicationClassLoader()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set explicit class loader to use when searching for Java classes.
|
||||
*
|
||||
* @see #getApplicationClassLoader()
|
||||
*/
|
||||
public final void initApplicationClassLoader(ClassLoader loader)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this is a sealed ContextFactory.
|
||||
* @see #seal()
|
||||
*/
|
||||
public final boolean isSealed()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seal this ContextFactory so any attempt to modify it like to add or
|
||||
* remove its listeners will throw an exception.
|
||||
* @see #isSealed()
|
||||
*/
|
||||
public final void seal()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a context associated with the current thread, creating one if need
|
||||
* be. The Context stores the execution state of the JavaScript engine, so
|
||||
* it is required that the context be entered before execution may begin.
|
||||
* Once a thread has entered a Context, then getCurrentContext() may be
|
||||
* called to find the context that is associated with the current thread.
|
||||
* <p>
|
||||
* Calling <code>enterContext()</code> will return either the Context
|
||||
* currently associated with the thread, or will create a new context and
|
||||
* associate it with the current thread. Each call to
|
||||
* <code>enterContext()</code> must have a matching call to
|
||||
* {@link Context#exit()}.
|
||||
* <pre>
|
||||
* Context cx = contextFactory.enterContext();
|
||||
* try {
|
||||
* ...
|
||||
* cx.evaluateString(...);
|
||||
* } finally {
|
||||
* Context.exit();
|
||||
* }
|
||||
* </pre>
|
||||
* Instead of using <code>enterContext()</code>, <code>exit()</code> pair consider
|
||||
* using {@link #call(ContextAction)} which guarantees proper association
|
||||
* of Context instances with the current thread.
|
||||
* With this method the above example becomes:
|
||||
* <pre>
|
||||
* ContextFactory.call(new ContextAction() {
|
||||
* public Object run(Context cx) {
|
||||
* ...
|
||||
* cx.evaluateString(...);
|
||||
* return null;
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* @return a Context associated with the current thread
|
||||
* @see Context#getCurrentContext()
|
||||
* @see Context#exit()
|
||||
* @see #call(ContextAction)
|
||||
*/
|
||||
public Context enterContext()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #enterContext()} instead
|
||||
* @return a Context associated with the current thread
|
||||
*/
|
||||
@Deprecated
|
||||
public final Context enter()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Context#exit()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public final void exit()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Context associated with the current thread, using the given
|
||||
* Context if need be.
|
||||
* <p>
|
||||
* The same as <code>enterContext()</code> except that <code>cx</code>
|
||||
* is associated with the current thread and returned if the current thread
|
||||
* has no associated context and <code>cx</code> is not associated with any
|
||||
* other thread.
|
||||
* @param cx a Context to associate with the thread if possible
|
||||
* @return a Context associated with the current thread
|
||||
* @see #enterContext()
|
||||
* @see #call(ContextAction)
|
||||
* @throws IllegalStateException if <code>cx</code> is already associated
|
||||
* with a different thread
|
||||
*/
|
||||
public final Context enterContext(Context cx)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* Load generated classes.
|
||||
*
|
||||
* @author Norris Boyd
|
||||
*/
|
||||
public class DefiningClassLoader extends ClassLoader
|
||||
implements GeneratedClassLoader
|
||||
{
|
||||
public DefiningClassLoader() {
|
||||
}
|
||||
|
||||
public DefiningClassLoader(ClassLoader parentLoader) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> defineClass(String name, byte[] data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void linkClass(Class<?> cl) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name, boolean resolve)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* This is interface that all functions in JavaScript must implement. The interface provides for
|
||||
* calling functions and constructors.
|
||||
*
|
||||
* @see org.mozilla.javascript.Scriptable
|
||||
* @author Norris Boyd
|
||||
*/
|
||||
public interface Function extends Scriptable {
|
||||
/**
|
||||
* Call the function.
|
||||
*
|
||||
* <p>Note that the array of arguments is not guaranteed to have length greater than 0.
|
||||
*
|
||||
* @param cx the current Context for this thread
|
||||
* @param scope the scope to execute the function relative to. This is set to the value returned
|
||||
* by getParentScope() except when the function is called from a closure.
|
||||
* @param thisObj the JavaScript <code>this</code> object
|
||||
* @param args the array of arguments
|
||||
* @return the result of the call
|
||||
*/
|
||||
Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args);
|
||||
|
||||
/**
|
||||
* Call the function as a constructor.
|
||||
*
|
||||
* <p>This method is invoked by the runtime in order to satisfy a use of the JavaScript <code>
|
||||
* new</code> operator. This method is expected to create a new object and return it.
|
||||
*
|
||||
* @param cx the current Context for this thread
|
||||
* @param scope an enclosing scope of the caller except when the function is called from a
|
||||
* closure.
|
||||
* @param args the array of arguments
|
||||
* @return the allocated object
|
||||
*/
|
||||
Scriptable construct(Context cx, Scriptable scope, Object[] args);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* Interface to define classes from generated byte code.
|
||||
*/
|
||||
public interface GeneratedClassLoader {
|
||||
|
||||
/**
|
||||
* Define a new Java class.
|
||||
* Classes created via this method should have the same class loader.
|
||||
*
|
||||
* @param name fully qualified class name
|
||||
* @param data class byte code
|
||||
* @return new class object
|
||||
*/
|
||||
public Class<?> defineClass(String name, byte[] data);
|
||||
|
||||
/**
|
||||
* Link the given class.
|
||||
*
|
||||
* @param cl Class instance returned from the previous call to
|
||||
* {@link #defineClass(String, byte[])}
|
||||
* @see java.lang.ClassLoader
|
||||
*/
|
||||
public void linkClass(Class<?> cl);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* The class of exceptions thrown by the JavaScript engine.
|
||||
*/
|
||||
public abstract class RhinoException extends RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* All compiled scripts implement this interface.
|
||||
* <p>
|
||||
* This class encapsulates script execution relative to an
|
||||
* object scope.
|
||||
* @since 1.3
|
||||
* @author Norris Boyd
|
||||
*/
|
||||
|
||||
public interface Script {
|
||||
|
||||
/**
|
||||
* Execute the script.
|
||||
* <p>
|
||||
* The script is executed in a particular runtime Context, which
|
||||
* must be associated with the current thread.
|
||||
* The script is executed relative to a scope--definitions and
|
||||
* uses of global top-level variables and functions will access
|
||||
* properties of the scope object. For compliant ECMA
|
||||
* programs, the scope must be an object that has been initialized
|
||||
* as a global object using <code>Context.initStandardObjects</code>.
|
||||
* <p>
|
||||
*
|
||||
* @param cx the Context associated with the current thread
|
||||
* @param scope the scope to execute relative to
|
||||
* @return the result of executing the script
|
||||
* @see org.mozilla.javascript.Context#initStandardObjects()
|
||||
*/
|
||||
public Object exec(Context cx, Scriptable scope);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* This is interface that all objects in JavaScript must implement.
|
||||
* The interface provides for the management of properties and for
|
||||
* performing conversions.
|
||||
* <p>
|
||||
* Host system implementors may find it easier to extend the ScriptableObject
|
||||
* class rather than implementing Scriptable when writing host objects.
|
||||
* <p>
|
||||
* There are many static methods defined in ScriptableObject that perform
|
||||
* the multiple calls to the Scriptable interface needed in order to
|
||||
* manipulate properties in prototype chains.
|
||||
* <p>
|
||||
*
|
||||
* @see org.mozilla.javascript.ScriptableObject
|
||||
* @author Norris Boyd
|
||||
* @author Nick Thompson
|
||||
* @author Brendan Eich
|
||||
*/
|
||||
|
||||
public interface Scriptable {
|
||||
|
||||
/**
|
||||
* Get the name of the set of objects implemented by this Java class.
|
||||
* This corresponds to the [[Class]] operation in ECMA and is used
|
||||
* by Object.prototype.toString() in ECMA.<p>
|
||||
* See ECMA 8.6.2 and 15.2.4.2.
|
||||
*/
|
||||
public String getClassName();
|
||||
|
||||
/**
|
||||
* Get a named property from the object.
|
||||
*
|
||||
* Looks property up in this object and returns the associated value
|
||||
* if found. Returns NOT_FOUND if not found.
|
||||
* Note that this method is not expected to traverse the prototype
|
||||
* chain. This is different from the ECMA [[Get]] operation.
|
||||
*
|
||||
* Depending on the property selector, the runtime will call
|
||||
* this method or the form of <code>get</code> that takes an
|
||||
* integer:
|
||||
* <table>
|
||||
* <tr><th>JavaScript code</th><th>Java code</th></tr>
|
||||
* <tr><td>a.b </td><td>a.get("b", a)</td></tr>
|
||||
* <tr><td>a["foo"] </td><td>a.get("foo", a)</td></tr>
|
||||
* <tr><td>a[3] </td><td>a.get(3, a)</td></tr>
|
||||
* <tr><td>a["3"] </td><td>a.get(3, a)</td></tr>
|
||||
* <tr><td>a[3.0] </td><td>a.get(3, a)</td></tr>
|
||||
* <tr><td>a["3.0"] </td><td>a.get("3.0", a)</td></tr>
|
||||
* <tr><td>a[1.1] </td><td>a.get("1.1", a)</td></tr>
|
||||
* <tr><td>a[-4] </td><td>a.get(-4, a)</td></tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* The values that may be returned are limited to the following:
|
||||
* <UL>
|
||||
* <LI>java.lang.Boolean objects</LI>
|
||||
* <LI>java.lang.String objects</LI>
|
||||
* <LI>java.lang.Number objects</LI>
|
||||
* <LI>org.mozilla.javascript.Scriptable objects</LI>
|
||||
* <LI>null</LI>
|
||||
* <LI>The value returned by Context.getUndefinedValue()</LI>
|
||||
* <LI>NOT_FOUND</LI>
|
||||
* </UL>
|
||||
* @param name the name of the property
|
||||
* @param start the object in which the lookup began
|
||||
* @return the value of the property (may be null), or NOT_FOUND
|
||||
* @see org.mozilla.javascript.Context#getUndefinedValue
|
||||
*/
|
||||
public Object get(String name, Scriptable start);
|
||||
|
||||
/**
|
||||
* Get a property from the object selected by an integral index.
|
||||
*
|
||||
* Identical to <code>get(String, Scriptable)</code> except that
|
||||
* an integral index is used to select the property.
|
||||
*
|
||||
* @param index the numeric index for the property
|
||||
* @param start the object in which the lookup began
|
||||
* @return the value of the property (may be null), or NOT_FOUND
|
||||
* @see org.mozilla.javascript.Scriptable#get(String,Scriptable)
|
||||
*/
|
||||
public Object get(int index, Scriptable start);
|
||||
|
||||
/**
|
||||
* Indicates whether or not a named property is defined in an object.
|
||||
*
|
||||
* Does not traverse the prototype chain.<p>
|
||||
*
|
||||
* The property is specified by a String name
|
||||
* as defined for the <code>get</code> method.<p>
|
||||
*
|
||||
* @param name the name of the property
|
||||
* @param start the object in which the lookup began
|
||||
* @return true if and only if the named property is found in the object
|
||||
* @see org.mozilla.javascript.Scriptable#get(String, Scriptable)
|
||||
* @see org.mozilla.javascript.ScriptableObject#getProperty(Scriptable, String)
|
||||
*/
|
||||
public boolean has(String name, Scriptable start);
|
||||
|
||||
/**
|
||||
* Indicates whether or not an indexed property is defined in an object.
|
||||
*
|
||||
* Does not traverse the prototype chain.<p>
|
||||
*
|
||||
* The property is specified by an integral index
|
||||
* as defined for the <code>get</code> method.<p>
|
||||
*
|
||||
* @param index the numeric index for the property
|
||||
* @param start the object in which the lookup began
|
||||
* @return true if and only if the indexed property is found in the object
|
||||
* @see org.mozilla.javascript.Scriptable#get(int, Scriptable)
|
||||
* @see org.mozilla.javascript.ScriptableObject#getProperty(Scriptable, int)
|
||||
*/
|
||||
public boolean has(int index, Scriptable start);
|
||||
|
||||
/**
|
||||
* Sets a named property in this object.
|
||||
* <p>
|
||||
* The property is specified by a string name
|
||||
* as defined for <code>get</code>.
|
||||
* <p>
|
||||
* The possible values that may be passed in are as defined for
|
||||
* <code>get</code>. A class that implements this method may choose
|
||||
* to ignore calls to set certain properties, in which case those
|
||||
* properties are effectively read-only.<p>
|
||||
* For properties defined in a prototype chain,
|
||||
* use <code>putProperty</code> in ScriptableObject. <p>
|
||||
* Note that if a property <i>a</i> is defined in the prototype <i>p</i>
|
||||
* of an object <i>o</i>, then evaluating <code>o.a = 23</code> will cause
|
||||
* <code>set</code> to be called on the prototype <i>p</i> with
|
||||
* <i>o</i> as the <i>start</i> parameter.
|
||||
* To preserve JavaScript semantics, it is the Scriptable
|
||||
* object's responsibility to modify <i>o</i>. <p>
|
||||
* This design allows properties to be defined in prototypes and implemented
|
||||
* in terms of getters and setters of Java values without consuming slots
|
||||
* in each instance.
|
||||
* <p>
|
||||
* The values that may be set are limited to the following:
|
||||
* <UL>
|
||||
* <LI>java.lang.Boolean objects</LI>
|
||||
* <LI>java.lang.String objects</LI>
|
||||
* <LI>java.lang.Number objects</LI>
|
||||
* <LI>org.mozilla.javascript.Scriptable objects</LI>
|
||||
* <LI>null</LI>
|
||||
* <LI>The value returned by Context.getUndefinedValue()</LI>
|
||||
* </UL><p>
|
||||
* Arbitrary Java objects may be wrapped in a Scriptable by first calling
|
||||
* <code>Context.toObject</code>. This allows the property of a JavaScript
|
||||
* object to contain an arbitrary Java object as a value.<p>
|
||||
* Note that <code>has</code> will be called by the runtime first before
|
||||
* <code>set</code> is called to determine in which object the
|
||||
* property is defined.
|
||||
* Note that this method is not expected to traverse the prototype chain,
|
||||
* which is different from the ECMA [[Put]] operation.
|
||||
* @param name the name of the property
|
||||
* @param start the object whose property is being set
|
||||
* @param value value to set the property to
|
||||
* @see org.mozilla.javascript.Scriptable#has(String, Scriptable)
|
||||
* @see org.mozilla.javascript.Scriptable#get(String, Scriptable)
|
||||
* @see org.mozilla.javascript.ScriptableObject#putProperty(Scriptable, String, Object)
|
||||
* @see org.mozilla.javascript.Context#toObject(Object, Scriptable)
|
||||
*/
|
||||
public void put(String name, Scriptable start, Object value);
|
||||
|
||||
/**
|
||||
* Sets an indexed property in this object.
|
||||
* <p>
|
||||
* The property is specified by an integral index
|
||||
* as defined for <code>get</code>.<p>
|
||||
*
|
||||
* Identical to <code>put(String, Scriptable, Object)</code> except that
|
||||
* an integral index is used to select the property.
|
||||
*
|
||||
* @param index the numeric index for the property
|
||||
* @param start the object whose property is being set
|
||||
* @param value value to set the property to
|
||||
* @see org.mozilla.javascript.Scriptable#has(int, Scriptable)
|
||||
* @see org.mozilla.javascript.Scriptable#get(int, Scriptable)
|
||||
* @see org.mozilla.javascript.ScriptableObject#putProperty(Scriptable, int, Object)
|
||||
* @see org.mozilla.javascript.Context#toObject(Object, Scriptable)
|
||||
*/
|
||||
public void put(int index, Scriptable start, Object value);
|
||||
|
||||
/**
|
||||
* Removes a property from this object.
|
||||
* This operation corresponds to the ECMA [[Delete]] except that
|
||||
* the no result is returned. The runtime will guarantee that this
|
||||
* method is called only if the property exists. After this method
|
||||
* is called, the runtime will call Scriptable.has to see if the
|
||||
* property has been removed in order to determine the boolean
|
||||
* result of the delete operator as defined by ECMA 11.4.1.
|
||||
* <p>
|
||||
* A property can be made permanent by ignoring calls to remove
|
||||
* it.<p>
|
||||
* The property is specified by a String name
|
||||
* as defined for <code>get</code>.
|
||||
* <p>
|
||||
* To delete properties defined in a prototype chain,
|
||||
* see deleteProperty in ScriptableObject.
|
||||
* @param name the identifier for the property
|
||||
* @see org.mozilla.javascript.Scriptable#get(String, Scriptable)
|
||||
* @see org.mozilla.javascript.ScriptableObject#deleteProperty(Scriptable, String)
|
||||
*/
|
||||
public void delete(String name);
|
||||
|
||||
/**
|
||||
* Removes a property from this object.
|
||||
*
|
||||
* The property is specified by an integral index
|
||||
* as defined for <code>get</code>.
|
||||
* <p>
|
||||
* To delete properties defined in a prototype chain,
|
||||
* see deleteProperty in ScriptableObject.
|
||||
*
|
||||
* Identical to <code>delete(String)</code> except that
|
||||
* an integral index is used to select the property.
|
||||
*
|
||||
* @param index the numeric index for the property
|
||||
* @see org.mozilla.javascript.Scriptable#get(int, Scriptable)
|
||||
* @see org.mozilla.javascript.ScriptableObject#deleteProperty(Scriptable, int)
|
||||
*/
|
||||
public void delete(int index);
|
||||
|
||||
/**
|
||||
* Get the prototype of the object.
|
||||
* @return the prototype
|
||||
*/
|
||||
public Scriptable getPrototype();
|
||||
|
||||
/**
|
||||
* Set the prototype of the object.
|
||||
* @param prototype the prototype to set
|
||||
*/
|
||||
public void setPrototype(Scriptable prototype);
|
||||
|
||||
/**
|
||||
* Get the parent scope of the object.
|
||||
* @return the parent scope
|
||||
*/
|
||||
public Scriptable getParentScope();
|
||||
|
||||
/**
|
||||
* Set the parent scope of the object.
|
||||
* @param parent the parent scope to set
|
||||
*/
|
||||
public void setParentScope(Scriptable parent);
|
||||
|
||||
/**
|
||||
* Get an array of property ids.
|
||||
*
|
||||
* Not all property ids need be returned. Those properties
|
||||
* whose ids are not returned are considered non-enumerable.
|
||||
*
|
||||
* @return an array of Objects. Each entry in the array is either
|
||||
* a java.lang.String or a java.lang.Number
|
||||
*/
|
||||
public Object[] getIds();
|
||||
|
||||
/**
|
||||
* Get the default value of the object with a given hint.
|
||||
* The hints are String.class for type String, Number.class for type
|
||||
* Number, Scriptable.class for type Object, and Boolean.class for
|
||||
* type Boolean. <p>
|
||||
*
|
||||
* A <code>hint</code> of null means "no hint".
|
||||
*
|
||||
* See ECMA 8.6.2.6.
|
||||
*
|
||||
* @param hint the type hint
|
||||
* @return the default value
|
||||
*/
|
||||
public Object getDefaultValue(Class<?> hint);
|
||||
|
||||
/**
|
||||
* The instanceof operator.
|
||||
*
|
||||
* <p>
|
||||
* The JavaScript code "lhs instanceof rhs" causes rhs.hasInstance(lhs) to
|
||||
* be called.
|
||||
*
|
||||
* <p>
|
||||
* The return value is implementation dependent so that embedded host objects can
|
||||
* return an appropriate value. See the JS 1.3 language documentation for more
|
||||
* detail.
|
||||
*
|
||||
* <p>This operator corresponds to the proposed EMCA [[HasInstance]] operator.
|
||||
*
|
||||
* @param instance The value that appeared on the LHS of the instanceof
|
||||
* operator
|
||||
*
|
||||
* @return an implementation dependent value
|
||||
*/
|
||||
public boolean hasInstance(Scriptable instance);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// API class
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* This is the default implementation of the Scriptable interface. This
|
||||
* class provides convenient default behavior that makes it easier to
|
||||
* define host objects.
|
||||
* <p>
|
||||
* Various properties and methods of JavaScript objects can be conveniently
|
||||
* defined using methods of ScriptableObject.
|
||||
* <p>
|
||||
* Classes extending ScriptableObject must define the getClassName method.
|
||||
*
|
||||
* @see org.mozilla.javascript.Scriptable
|
||||
* @author Norris Boyd
|
||||
*/
|
||||
|
||||
public abstract class ScriptableObject implements Scriptable
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.javascript.optimizer;
|
||||
|
||||
import org.mozilla.javascript.CompilerEnvirons;
|
||||
|
||||
/**
|
||||
* Generates class files from script sources.
|
||||
*
|
||||
* since 1.5 Release 5
|
||||
* @author Igor Bukanov
|
||||
*/
|
||||
|
||||
public class ClassCompiler
|
||||
{
|
||||
/**
|
||||
* Construct ClassCompiler that uses the specified compiler environment
|
||||
* when generating classes.
|
||||
*/
|
||||
public ClassCompiler(CompilerEnvirons compilerEnv)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class name to use for main method implementation.
|
||||
* The class must have a method matching
|
||||
* <code>public static void main(Script sc, String[] args)</code>, it will be
|
||||
* called when <code>main(String[] args)</code> is called in the generated
|
||||
* class. The class name should be fully qulified name and include the
|
||||
* package name like in <code>org.foo.Bar</code>.
|
||||
*/
|
||||
public void setMainMethodClass(String className)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the class for main method implementation.
|
||||
* @see #setMainMethodClass(String)
|
||||
*/
|
||||
public String getMainMethodClass()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the compiler environment the compiler uses.
|
||||
*/
|
||||
public CompilerEnvirons getCompilerEnv()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class that the generated target will extend.
|
||||
*/
|
||||
public Class<?> getTargetExtends()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class that the generated target will extend.
|
||||
*
|
||||
* @param extendsClass the class it extends
|
||||
*/
|
||||
public void setTargetExtends(Class<?> extendsClass)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the interfaces that the generated target will implement.
|
||||
*/
|
||||
public Class<?>[] getTargetImplements()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the interfaces that the generated target will implement.
|
||||
*
|
||||
* @param implementsClasses an array of Class objects, one for each
|
||||
* interface the target will extend
|
||||
*/
|
||||
public void setTargetImplements(Class<?>[] implementsClasses)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile JavaScript source into one or more Java class files.
|
||||
* The first compiled class will have name mainClassName.
|
||||
* If the results of {@link #getTargetExtends()} or
|
||||
* {@link #getTargetImplements()} are not null, then the first compiled
|
||||
* class will extend the specified super class and implement
|
||||
* specified interfaces.
|
||||
*
|
||||
* @return array where elements with even indexes specifies class name
|
||||
* and the following odd index gives class file body as byte[]
|
||||
* array. The initial element of the array always holds
|
||||
* mainClassName and array[1] holds its byte code.
|
||||
*/
|
||||
public Object[] compileToClassFiles(String source,
|
||||
String sourceLocation,
|
||||
int lineno,
|
||||
String mainClassName)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -3,33 +3,53 @@ import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
|
||||
class Test {
|
||||
public static class Potato {
|
||||
private String name;
|
||||
|
||||
private String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public static String taint() {
|
||||
return "tainted";
|
||||
}
|
||||
|
||||
public static void sink(Object any) {}
|
||||
|
||||
public static void jacksonObjectMapper() throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException {
|
||||
String s = taint();
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
File file = new File("testFile");
|
||||
om.writeValue(file, s);
|
||||
sink(file); //$hasTaintFlow
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
om.writeValue(out, s);
|
||||
sink(file); //$hasTaintFlow
|
||||
Writer writer = new StringWriter();
|
||||
om.writeValue(writer, s);
|
||||
sink(writer); //$hasTaintFlow
|
||||
JsonGenerator generator = new JsonFactory().createGenerator(new StringWriter());
|
||||
om.writeValue(generator, s);
|
||||
sink(generator); //$hasTaintFlow
|
||||
String t = om.writeValueAsString(s);
|
||||
System.out.println(t);
|
||||
sink(t); //$hasTaintFlow
|
||||
byte[] bs = om.writeValueAsBytes(s);
|
||||
String reconstructed = new String(bs, "utf-8");
|
||||
System.out.println(reconstructed);
|
||||
sink(bs); //$hasTaintFlow
|
||||
sink(reconstructed); //$hasTaintFlow
|
||||
}
|
||||
|
||||
public static void jacksonObjectWriter() throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException {
|
||||
@@ -37,16 +57,56 @@ class Test {
|
||||
ObjectWriter ow = new ObjectWriter();
|
||||
File file = new File("testFile");
|
||||
ow.writeValue(file, s);
|
||||
sink(file); //$hasTaintFlow
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
ow.writeValue(out, s);
|
||||
sink(out); //$hasTaintFlow
|
||||
Writer writer = new StringWriter();
|
||||
ow.writeValue(writer, s);
|
||||
sink(writer); //$hasTaintFlow
|
||||
JsonGenerator generator = new JsonFactory().createGenerator(new StringWriter());
|
||||
ow.writeValue(generator, s);
|
||||
sink(generator); //$hasTaintFlow
|
||||
String t = ow.writeValueAsString(s);
|
||||
System.out.println(t);
|
||||
sink(t); //$hasTaintFlow
|
||||
byte[] bs = ow.writeValueAsBytes(s);
|
||||
String reconstructed = new String(bs, "utf-8");
|
||||
System.out.println(reconstructed);
|
||||
sink(bs); //$hasTaintFlow
|
||||
sink(reconstructed); //$hasTaintFlow
|
||||
}
|
||||
|
||||
public static void jacksonObjectReader() throws java.io.IOException {
|
||||
String s = taint();
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
ObjectReader reader = om.readerFor(Potato.class);
|
||||
sink(reader.readValue(s)); //$hasTaintFlow
|
||||
sink(reader.readValue(s, Potato.class).name); //$hasTaintFlow
|
||||
sink(reader.readValue(s, Potato.class).getName()); //$hasTaintFlow
|
||||
}
|
||||
|
||||
public static void jacksonObjectReaderIterable() throws java.io.IOException {
|
||||
String s = taint();
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
ObjectReader reader = om.readerFor(Potato.class);
|
||||
sink(reader.readValues(s)); //$hasTaintFlow
|
||||
Iterator<Potato> pIterator = reader.readValues(s, Potato.class);
|
||||
while(pIterator.hasNext()) {
|
||||
Potato p = pIterator.next();
|
||||
sink(p); //$hasTaintFlow
|
||||
sink(p.name); //$hasTaintFlow
|
||||
sink(p.getName()); //$hasTaintFlow
|
||||
}
|
||||
}
|
||||
|
||||
public static void jacksonTwoStepDeserialization() throws java.io.IOException {
|
||||
String s = taint();
|
||||
Map<String, Object> taintedParams = new HashMap<>();
|
||||
taintedParams.put("name", s);
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
JsonNode jn = om.valueToTree(taintedParams);
|
||||
sink(jn); //$hasTaintFlow
|
||||
Potato p = om.convertValue(jn, Potato.class);
|
||||
sink(p); //$hasTaintFlow
|
||||
sink(p.getName()); //$hasTaintFlow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:10:43:10:54 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:13:73:13:84 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:16:44:16:55 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:19:36:19:47 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:22:35:22:46 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectMapper.java:26:36:26:47 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:10:43:10:54 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:13:73:13:84 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:16:44:16:55 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:19:36:19:47 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:22:35:22:46 | value |
|
||||
| ../../../stubs/jackson-databind-2.10/com/fasterxml/jackson/databind/ObjectWriter.java:26:36:26:47 | value |
|
||||
| Test.java:18:14:18:20 | taint(...) |
|
||||
| Test.java:21:17:21:20 | file [post update] |
|
||||
| Test.java:21:23:21:23 | s |
|
||||
| Test.java:22:43:22:46 | file |
|
||||
| Test.java:23:17:23:19 | out [post update] |
|
||||
| Test.java:23:22:23:22 | s |
|
||||
| Test.java:25:17:25:22 | writer [post update] |
|
||||
| Test.java:25:25:25:25 | s |
|
||||
| Test.java:27:17:27:25 | generator [post update] |
|
||||
| Test.java:27:28:27:28 | s |
|
||||
| Test.java:28:14:28:37 | writeValueAsString(...) |
|
||||
| Test.java:28:36:28:36 | s |
|
||||
| Test.java:29:22:29:22 | t |
|
||||
| Test.java:30:15:30:37 | writeValueAsBytes(...) |
|
||||
| Test.java:30:36:30:36 | s |
|
||||
| Test.java:31:26:31:48 | new String(...) |
|
||||
| Test.java:31:37:31:38 | bs |
|
||||
| Test.java:32:22:32:34 | reconstructed |
|
||||
| Test.java:36:14:36:20 | taint(...) |
|
||||
| Test.java:39:17:39:20 | file [post update] |
|
||||
| Test.java:39:23:39:23 | s |
|
||||
| Test.java:40:43:40:46 | file |
|
||||
| Test.java:41:17:41:19 | out [post update] |
|
||||
| Test.java:41:22:41:22 | s |
|
||||
| Test.java:43:17:43:22 | writer [post update] |
|
||||
| Test.java:43:25:43:25 | s |
|
||||
| Test.java:45:17:45:25 | generator [post update] |
|
||||
| Test.java:45:28:45:28 | s |
|
||||
| Test.java:46:14:46:37 | writeValueAsString(...) |
|
||||
| Test.java:46:36:46:36 | s |
|
||||
| Test.java:47:22:47:22 | t |
|
||||
| Test.java:48:15:48:37 | writeValueAsBytes(...) |
|
||||
| Test.java:48:36:48:36 | s |
|
||||
| Test.java:49:26:49:48 | new String(...) |
|
||||
| Test.java:49:37:49:38 | bs |
|
||||
| Test.java:50:22:50:34 | reconstructed |
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class Conf extends TaintTracking::Configuration {
|
||||
Conf() { this = "qltest:dataflow:jackson" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(MethodAccess).getMethod().hasName("taint")
|
||||
override predicate isSource(DataFlow::Node n) {
|
||||
n.asExpr().(MethodAccess).getMethod().hasName("taint")
|
||||
or
|
||||
n instanceof RemoteFlowSource
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { any() }
|
||||
override predicate isSink(DataFlow::Node n) {
|
||||
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::Node source, DataFlow::Node sink, Conf config
|
||||
where config.hasFlow(source, sink)
|
||||
select sink
|
||||
class HasFlowTest extends InlineExpectationsTest {
|
||||
HasFlowTest() { this = "HasFlowTest" }
|
||||
|
||||
override string getARelevantTag() { result = "hasTaintFlow" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasTaintFlow" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink, Conf conf | conf.hasFlow(src, sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
34
java/ql/test/query-tests/security/CWE-502/KryoTest.java
Normal file
34
java/ql/test/query-tests/security/CWE-502/KryoTest.java
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
import com.esotericsoftware.kryo.pool.KryoPool;
|
||||
import com.esotericsoftware.kryo.io.Input;
|
||||
|
||||
public class KryoTest {
|
||||
|
||||
private Kryo getSafeKryo() {
|
||||
Kryo kryo = new Kryo();
|
||||
kryo.setRegistrationRequired(true);
|
||||
// ... kryo.register(A.class) ...
|
||||
return kryo;
|
||||
}
|
||||
|
||||
public void kryoDeserialize(Socket sock) throws java.io.IOException {
|
||||
KryoPool kryoPool = new KryoPool.Builder(this::getSafeKryo).softReferences().build();
|
||||
Input input = new Input(sock.getInputStream());
|
||||
Object o = kryoPool.run(kryo -> kryo.readClassAndObject(input)); // OK
|
||||
}
|
||||
|
||||
public void kryoDeserialize2(Socket sock) throws java.io.IOException {
|
||||
KryoPool kryoPool = new KryoPool.Builder(this::getSafeKryo).softReferences().build();
|
||||
Input input = new Input(sock.getInputStream());
|
||||
Kryo k = kryoPool.borrow();
|
||||
try {
|
||||
Object o = k.readClassAndObject(input); // OK
|
||||
} finally {
|
||||
kryoPool.release(k);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.fasterxml.jackson.databind;
|
||||
|
||||
public class JsonNode {
|
||||
import java.util.*;
|
||||
|
||||
public abstract class JsonNode implements Iterable<JsonNode> {
|
||||
public JsonNode() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.fasterxml.jackson.databind;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class MappingIterator<T> implements Iterator<T>, Closeable {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -26,4 +26,16 @@ public class ObjectMapper {
|
||||
public String writeValueAsString(Object value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ObjectReader readerFor(Class<?> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T extends JsonNode> T valueToTree(Object fromValue) throws IllegalArgumentException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T convertValue(Object fromValue, Class<T> toValueType) throws IllegalArgumentException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.fasterxml.jackson.databind;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class ObjectReader {
|
||||
public ObjectReader forType(Class<?> valueType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(String src) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(String src, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(byte[] content) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(byte[] content, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(File src) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(InputStream src) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(InputStream src, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(Reader src) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> T readValue(Reader src, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(String src) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(String src, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(byte[] content) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(byte[] content, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(File src) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(InputStream src) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(InputStream src, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(Reader src) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> MappingIterator<T> readValues(Reader src, Class<T> valueType) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// Autogenerated AST node
|
||||
package org.python.antlr.base;
|
||||
|
||||
public abstract class mod {
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Corporation for National Research Initiatives
|
||||
package org.python.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class for loading compiled Python modules and Java classes defined in Python modules.
|
||||
*/
|
||||
public class BytecodeLoader {
|
||||
|
||||
/**
|
||||
* Turn the Java class file data into a Java class.
|
||||
*
|
||||
* @param name fully-qualified binary name of the class
|
||||
* @param data a class file as a byte array
|
||||
* @param referents super-classes and interfaces that the new class will reference.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Class<?> makeClass(String name, byte[] data, Class<?>... referents) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the Java class file data into a Java class.
|
||||
*
|
||||
* @param name the name of the class
|
||||
* @param referents super-classes and interfaces that the new class will reference.
|
||||
* @param data a class file as a byte array
|
||||
*/
|
||||
public static Class<?> makeClass(String name, List<Class<?>> referents, byte[] data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the Java class file data for a compiled Python module into a {@code PyCode} object, by
|
||||
* constructing an instance of the named class and calling the instance's
|
||||
* {@link PyRunnable#getMain()}.
|
||||
*
|
||||
* @param name fully-qualified binary name of the class
|
||||
* @param data a class file as a byte array
|
||||
* @param filename to provide to the constructor of the named class
|
||||
* @return the {@code PyCode} object produced by the named class' {@code getMain}
|
||||
*/
|
||||
public static PyCode makeCode(String name, byte[] data, String filename) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.python.core;
|
||||
|
||||
public enum CompileMode {
|
||||
eval,
|
||||
single,
|
||||
exec;
|
||||
|
||||
public static CompileMode getMode(String mode) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// At some future point this will also be extended - in conjunction with
|
||||
// Py#compileFlags - to add
|
||||
// support for a compiler factory that user code can choose in place of the
|
||||
// normal compiler.
|
||||
// (Perhaps a better name might have been "CompilerOptions".)
|
||||
|
||||
package org.python.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class CompilerFlags implements Serializable {
|
||||
public CompilerFlags() {
|
||||
}
|
||||
|
||||
public CompilerFlags(int co_flags) {
|
||||
}
|
||||
}
|
||||
134
java/ql/test/stubs/jython-2.7.2/org/python/core/Py.java
Normal file
134
java/ql/test/stubs/jython-2.7.2/org/python/core/Py.java
Normal file
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) Corporation for National Research Initiatives
|
||||
package org.python.core;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.python.antlr.base.mod;
|
||||
|
||||
public final class Py {
|
||||
/**
|
||||
Convert a given <code>PyObject</code> to an instance of a Java class.
|
||||
Identical to <code>o.__tojava__(c)</code> except that it will
|
||||
raise a <code>TypeError</code> if the conversion fails.
|
||||
@param o the <code>PyObject</code> to convert.
|
||||
@param c the class to convert it to.
|
||||
**/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T tojava(PyObject o, Class<T> c) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ??pending: was @deprecated but is actually used by proxie code.
|
||||
// Can get rid of it?
|
||||
public static Object tojava(PyObject o, String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the PyObjectAdapter passed to {@link PySystemState#initialize} to turn o into a PyObject.
|
||||
*
|
||||
* @see ClassicPyObjectAdapter - default PyObjectAdapter type
|
||||
*/
|
||||
public static PyObject java2py(Object o) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the PyObjectAdapter passed to {@link PySystemState#initialize} to turn
|
||||
* <code>objects</code> into an array of PyObjects.
|
||||
*
|
||||
* @see ClassicPyObjectAdapter - default PyObjectAdapter type
|
||||
*/
|
||||
public static PyObject[] javas2pys(Object... objects) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PyObject makeClass(String name, PyObject[] bases, PyCode code,
|
||||
PyObject[] closure_cells) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PyObject makeClass(String name, PyObject base, PyObject dict) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Python class.
|
||||
*
|
||||
* @param name the String name of the class
|
||||
* @param bases an array of PyObject base classes
|
||||
* @param dict the class's namespace, containing the class body
|
||||
* definition
|
||||
* @return a new Python Class PyObject
|
||||
*/
|
||||
public static PyObject makeClass(String name, PyObject[] bases, PyObject dict) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CompilerFlags getCompilerFlags() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CompilerFlags getCompilerFlags(int flags, boolean dont_inherit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CompilerFlags getCompilerFlags(CompilerFlags flags, boolean dont_inherit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// w/o compiler-flags
|
||||
public static PyCode compile(InputStream istream, String filename, CompileMode kind) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point for compiling modules.
|
||||
*
|
||||
* @param node Module node, coming from the parsing process
|
||||
* @param name Internal name for the compiled code. Typically generated by
|
||||
* calling {@link #getName()}.
|
||||
* @param filename Source file name
|
||||
* @param linenumbers True to track source line numbers on the generated
|
||||
* code
|
||||
* @param printResults True to call the sys.displayhook on the result of
|
||||
* the code
|
||||
* @param cflags Compiler flags
|
||||
* @return Code object for the compiled module
|
||||
*/
|
||||
public static PyCode compile_flags(mod node, String name, String filename,
|
||||
boolean linenumbers, boolean printResults,
|
||||
CompilerFlags cflags) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PyCode compile_flags(mod node, String filename,
|
||||
CompileMode kind, CompilerFlags cflags) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles python source code coming from a file or another external stream
|
||||
*/
|
||||
public static PyCode compile_flags(InputStream istream, String filename,
|
||||
CompileMode kind, CompilerFlags cflags) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles python source code coming from String (raw bytes) data.
|
||||
*
|
||||
* If the String is properly decoded (from PyUnicode) the PyCF_SOURCE_IS_UTF8 flag
|
||||
* should be specified.
|
||||
*/
|
||||
public static PyCode compile_flags(String data, String filename,
|
||||
CompileMode kind, CompilerFlags cflags) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PyObject compile_command_flags(String string, String filename,
|
||||
CompileMode kind, CompilerFlags cflags, boolean stdprompt) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
43
java/ql/test/stubs/jython-2.7.2/org/python/core/PyCode.java
Normal file
43
java/ql/test/stubs/jython-2.7.2/org/python/core/PyCode.java
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) Corporation for National Research Initiatives
|
||||
package org.python.core;
|
||||
|
||||
/**
|
||||
* A super class for all python code implementations.
|
||||
*/
|
||||
public abstract class PyCode extends PyObject
|
||||
{
|
||||
abstract public PyObject call(ThreadState state,
|
||||
PyObject args[], String keywords[],
|
||||
PyObject globals, PyObject[] defaults,
|
||||
PyObject closure);
|
||||
|
||||
abstract public PyObject call(ThreadState state,
|
||||
PyObject self, PyObject args[],
|
||||
String keywords[],
|
||||
PyObject globals, PyObject[] defaults,
|
||||
PyObject closure);
|
||||
|
||||
abstract public PyObject call(ThreadState state,
|
||||
PyObject globals, PyObject[] defaults,
|
||||
PyObject closure);
|
||||
|
||||
abstract public PyObject call(ThreadState state,
|
||||
PyObject arg1, PyObject globals,
|
||||
PyObject[] defaults, PyObject closure);
|
||||
|
||||
abstract public PyObject call(ThreadState state,
|
||||
PyObject arg1, PyObject arg2,
|
||||
PyObject globals, PyObject[] defaults,
|
||||
PyObject closure);
|
||||
|
||||
abstract public PyObject call(ThreadState state,
|
||||
PyObject arg1, PyObject arg2, PyObject arg3,
|
||||
PyObject globals, PyObject[] defaults,
|
||||
PyObject closure);
|
||||
|
||||
abstract public PyObject call(ThreadState state,
|
||||
PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4,
|
||||
PyObject globals, PyObject[] defaults,
|
||||
PyObject closure);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Corporation for National Research Initiatives
|
||||
package org.python.core;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* A wrapper for all python exception. Note that the well-known python exceptions are <b>not</b>
|
||||
* subclasses of PyException. Instead the python exception class is stored in the <code>type</code>
|
||||
* field and value or class instance is stored in the <code>value</code> field.
|
||||
*/
|
||||
public class PyException extends RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) Corporation for National Research Initiatives
|
||||
package org.python.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* All objects known to the Jython runtime system are represented by an instance of the class
|
||||
* {@code PyObject} or one of its subclasses.
|
||||
*/
|
||||
public class PyObject implements Serializable {
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
// Copyright (c) Corporation for National Research Initiatives
|
||||
package org.python.core;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* The "sys" module.
|
||||
*/
|
||||
// xxx Many have lamented, this should really be a module!
|
||||
// but it will require some refactoring to see this wish come true.
|
||||
public class PySystemState extends PyObject {
|
||||
public PySystemState() {
|
||||
}
|
||||
|
||||
public static void classDictInit(PyObject dict) {
|
||||
}
|
||||
|
||||
public ClassLoader getSyspathJavaLoader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// xxx fix this accessors
|
||||
public PyObject __findattr_ex__(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void __setattr__(String name, PyObject value) {
|
||||
}
|
||||
|
||||
public void __delattr__(String name) {
|
||||
}
|
||||
|
||||
public PyObject gettrace() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void settrace(PyObject tracefunc) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the current working directory to the specified path.
|
||||
*
|
||||
* path is assumed to be absolute and canonical (via os.path.realpath).
|
||||
*
|
||||
* @param path a path String
|
||||
*/
|
||||
public void setCurrentWorkingDir(String path) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representing the current working directory.
|
||||
*
|
||||
* @return a path String
|
||||
*/
|
||||
public String getCurrentWorkingDir() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a path. Returns the full path taking the current working directory into account.
|
||||
*
|
||||
* @param path a path String
|
||||
* @return a resolved path String
|
||||
*/
|
||||
public String getPath(String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a path, returning a {@link File}, taking the current working directory into account.
|
||||
*
|
||||
* @param path a path <code>String</code>
|
||||
* @return a resolved <code>File</code>
|
||||
*/
|
||||
public File getFile(String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setClassLoader(ClassLoader classLoader) {
|
||||
}
|
||||
|
||||
public static Properties getBaseProperties() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static synchronized void initialize() {
|
||||
}
|
||||
|
||||
public static synchronized void initialize(Properties preProperties,
|
||||
Properties postProperties) {
|
||||
}
|
||||
|
||||
public static synchronized void initialize(Properties preProperties, Properties postProperties,
|
||||
String[] argv) {
|
||||
}
|
||||
|
||||
public static synchronized void initialize(Properties preProperties, Properties postProperties,
|
||||
String[] argv, ClassLoader classLoader) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a classpath directory to the list of places that are searched for java packages.
|
||||
* <p>
|
||||
* <b>Note</b>. Classes found in directory and sub-directory are not made available to jython by
|
||||
* this call. It only makes the java package found in the directory available. This call is
|
||||
* mostly useful if jython is embedded in an application that deals with its own class loaders.
|
||||
* A servlet container is a very good example. Calling
|
||||
* {@code add_classdir("<context>/WEB-INF/classes")} makes the java packages in WEB-INF classes
|
||||
* available to jython import. However the actual class loading is completely handled by the
|
||||
* servlet container's context classloader.
|
||||
*/
|
||||
public static void add_classdir(String directoryPath) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a .jar and .zip directory to the list of places that are searched for java .jar and .zip
|
||||
* files. The .jar and .zip files found will not be cached.
|
||||
* <p>
|
||||
* <b>Note</b>. Classes in .jar and .zip files found in the directory are not made available to
|
||||
* jython by this call. See the note for add_classdir(dir) for more details.
|
||||
*
|
||||
* @param directoryPath The name of a directory.
|
||||
*
|
||||
* @see #add_classdir
|
||||
*/
|
||||
public static void add_extdir(String directoryPath) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a .jar and .zip directory to the list of places that are searched for java .jar and .zip
|
||||
* files.
|
||||
* <p>
|
||||
* <b>Note</b>. Classes in .jar and .zip files found in the directory are not made available to
|
||||
* jython by this call. See the note for add_classdir(dir) for more details.
|
||||
*
|
||||
* @param directoryPath The name of a directory.
|
||||
* @param cache Controls if the packages in the zip and jar file should be cached.
|
||||
*
|
||||
* @see #add_classdir
|
||||
*/
|
||||
public static void add_extdir(String directoryPath, boolean cache) {
|
||||
}
|
||||
|
||||
// Not public by design. We can't rebind the displayhook if
|
||||
// a reflected function is inserted in the class dict.
|
||||
|
||||
/**
|
||||
* Exit a Python program with the given status.
|
||||
*
|
||||
* @param status the value to exit with
|
||||
* @throws PyException {@code SystemExit} always throws this exception. When caught at top level
|
||||
* the program will exit.
|
||||
*/
|
||||
public static void exit(PyObject status) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit a Python program with the status 0.
|
||||
*/
|
||||
public static void exit() {
|
||||
}
|
||||
|
||||
public static void exc_clear() {
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Corporation for National Research Initiatives
|
||||
package org.python.core;
|
||||
|
||||
// a ThreadState refers to one PySystemState; this weak ref allows for tracking all ThreadState objects
|
||||
// that refer to a given PySystemState
|
||||
|
||||
public class ThreadState {
|
||||
|
||||
public PyException exception;
|
||||
|
||||
public ThreadState(PySystemState systemState) {
|
||||
setSystemState(systemState);
|
||||
}
|
||||
|
||||
public void setSystemState(PySystemState systemState) {
|
||||
}
|
||||
|
||||
public PySystemState getSystemState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean enterRepr(PyObject obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void exitRepr(PyObject obj) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) Corporation for National Research Initiatives
|
||||
package org.python.util;
|
||||
|
||||
import org.python.core.*;
|
||||
|
||||
/**
|
||||
* This class provides the interface for compiling and running code that supports an interactive
|
||||
* interpreter.
|
||||
*/
|
||||
// Based on CPython-1.5.2's code module
|
||||
public class InteractiveInterpreter extends PythonInterpreter {
|
||||
|
||||
/**
|
||||
* Construct an InteractiveInterpreter with all default characteristics: default state (from
|
||||
* {@link Py#getSystemState()}), and a new empty dictionary of local variables.
|
||||
* */
|
||||
public InteractiveInterpreter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an InteractiveInterpreter with state (from {@link Py#getSystemState()}), and the
|
||||
* specified dictionary of local variables.
|
||||
*
|
||||
* @param locals dictionary to use, or if <code>null</code>, a new empty one will be created
|
||||
*/
|
||||
public InteractiveInterpreter(PyObject locals) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an InteractiveInterpreter with, and system state the specified dictionary of local
|
||||
* variables.
|
||||
*
|
||||
* @param locals dictionary to use, or if <code>null</code>, a new empty one will be created
|
||||
* @param systemState interpreter state, or if <code>null</code> use {@link Py#getSystemState()}
|
||||
*/
|
||||
public InteractiveInterpreter(PyObject locals, PySystemState systemState) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile and run some source in the interpreter, in the mode {@link CompileMode#single} which
|
||||
* is used for incremental compilation at the interactive console, known as {@code <input>}.
|
||||
*
|
||||
* @param source Python code
|
||||
* @return <code>true</code> to indicate a partial statement was entered
|
||||
*/
|
||||
public boolean runsource(String source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile and run some source in the interpreter, in the mode {@link CompileMode#single} which
|
||||
* is used for incremental compilation at the interactive console.
|
||||
*
|
||||
* @param source Python code
|
||||
* @param filename name with which to label this console input (e.g. in error messages).
|
||||
* @return <code>true</code> to indicate a partial statement was entered
|
||||
*/
|
||||
public boolean runsource(String source, String filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile and run some source in the interpreter, according to the {@link CompileMode} given.
|
||||
* This method supports incremental compilation and interpretation through the return value,
|
||||
* where {@code true} signifies that more input is expected in order to complete the Python
|
||||
* statement. An interpreter can use this to decide whether to use {@code sys.ps1}
|
||||
* ("{@code >>> }") or {@code sys.ps2} ("{@code ... }") to prompt the next line. The arguments
|
||||
* are the same as the mandatory ones in the Python {@code compile()} command.
|
||||
* <p>
|
||||
* One the following can happen:
|
||||
* <ol>
|
||||
* <li>The input is incorrect; compilation raised an exception (SyntaxError or OverflowError). A
|
||||
* syntax traceback will be printed by calling {@link #showexception(PyException)}. Return is
|
||||
* {@code false}.</li>
|
||||
*
|
||||
* <li>The input is incomplete, and more input is required; compilation returned no code.
|
||||
* Nothing happens. Return is {@code true}.</li>
|
||||
*
|
||||
* <li>The input is complete; compilation returned a code object. The code is executed by
|
||||
* calling {@link #runcode(PyObject)} (which also handles run-time exceptions, except for
|
||||
* SystemExit). Return is {@code false}.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param source Python code
|
||||
* @param filename name with which to label this console input (e.g. in error messages).
|
||||
* @param kind of compilation required: {@link CompileMode#eval}, {@link CompileMode#exec} or
|
||||
* {@link CompileMode#single}
|
||||
* @return {@code true} to indicate a partial statement was provided
|
||||
*/
|
||||
public boolean runsource(String source, String filename, CompileMode kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a code object. When an exception occurs, {@link #showexception(PyException)} is
|
||||
* called to display a stack trace, except in the case of SystemExit, which is re-raised.
|
||||
* <p>
|
||||
* A note about KeyboardInterrupt: this exception may occur elsewhere in this code, and may not
|
||||
* always be caught. The caller should be prepared to deal with it.
|
||||
**/
|
||||
|
||||
// Make this run in another thread somehow????
|
||||
public void runcode(PyObject code) {
|
||||
}
|
||||
|
||||
public void showexception(PyException exc) {
|
||||
}
|
||||
|
||||
public void write(String data) {
|
||||
}
|
||||
|
||||
public void resetbuffer() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
package org.python.util;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.python.core.PyCode;
|
||||
import org.python.core.PyObject;
|
||||
|
||||
/**
|
||||
* The PythonInterpreter class is a standard wrapper for a Jython interpreter for embedding in a
|
||||
* Java application.
|
||||
*/
|
||||
public class PythonInterpreter implements Closeable {
|
||||
|
||||
/**
|
||||
* Initializes the Jython runtime. This should only be called once, before any other Python
|
||||
* objects (including PythonInterpreter) are created.
|
||||
*
|
||||
* @param preProperties A set of properties. Typically System.getProperties() is used.
|
||||
* preProperties override properties from the registry file.
|
||||
* @param postProperties Another set of properties. Values like python.home, python.path and all
|
||||
* other values from the registry files can be added to this property set.
|
||||
* postProperties override system properties and registry properties.
|
||||
* @param argv Command line arguments, assigned to sys.argv.
|
||||
*/
|
||||
public static void
|
||||
initialize(Properties preProperties, Properties postProperties, String[] argv) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new interpreter with an empty local namespace.
|
||||
*/
|
||||
public PythonInterpreter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new interpreter with the ability to maintain a separate local namespace for each
|
||||
* thread (set by invoking setLocals()).
|
||||
*
|
||||
* @param dict a Python mapping object (e.g., a dictionary) for use as the default namespace
|
||||
*/
|
||||
public static PythonInterpreter threadLocalStateInterpreter(PyObject dict) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new interpreter with a specified local namespace.
|
||||
*
|
||||
* @param dict a Python mapping object (e.g., a dictionary) for use as the namespace
|
||||
*/
|
||||
public PythonInterpreter(PyObject dict) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a Python object to use for the standard output stream, <code>sys.stdout</code>. This
|
||||
* stream is used in a byte-oriented way (mostly) that depends on the type of file-like object.
|
||||
* The behaviour as implemented is:
|
||||
* <table border=1>
|
||||
* <caption>Stream behaviour for various object types</caption>
|
||||
* <tr align=center>
|
||||
* <td></td>
|
||||
* <td colspan=3>Python type of object <code>o</code> written</td>
|
||||
* </tr>
|
||||
* <tr align=left>
|
||||
* <th></th>
|
||||
* <th><code>str/bytes</code></th>
|
||||
* <th><code>unicode</code></th>
|
||||
* <th>Any other type</th>
|
||||
* </tr>
|
||||
* <tr align=left>
|
||||
* <th>{@link PyFile}</th>
|
||||
* <td>as bytes directly</td>
|
||||
* <td>respect {@link PyFile#encoding}</td>
|
||||
* <td>call <code>str(o)</code> first</td>
|
||||
* </tr>
|
||||
* <tr align=left>
|
||||
* <th>{@link PyFileWriter}</th>
|
||||
* <td>each byte value as a <code>char</code></td>
|
||||
* <td>write as Java <code>char</code>s</td>
|
||||
* <td>call <code>o.toString()</code> first</td>
|
||||
* </tr>
|
||||
* <tr align=left>
|
||||
* <th>Other {@link PyObject} <code>f</code></th>
|
||||
* <td>invoke <code>f.write(str(o))</code></td>
|
||||
* <td>invoke <code>f.write(o)</code></td>
|
||||
* <td>invoke <code>f.write(str(o))</code></td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @param outStream Python file-like object to use as the output stream
|
||||
*/
|
||||
public void setOut(PyObject outStream) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a {@link java.io.Writer} to use for the standard output stream, <code>sys.stdout</code>.
|
||||
* The behaviour as implemented is to output each object <code>o</code> by calling
|
||||
* <code>o.toString()</code> and writing this as UTF-16.
|
||||
*
|
||||
* @param outStream to use as the output stream
|
||||
*/
|
||||
public void setOut(java.io.Writer outStream) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a {@link java.io.OutputStream} to use for the standard output stream.
|
||||
*
|
||||
* @param outStream OutputStream to use as output stream
|
||||
*/
|
||||
public void setOut(java.io.OutputStream outStream) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a Python object to use for the standard output stream, <code>sys.stderr</code>. This
|
||||
* stream is used in a byte-oriented way (mostly) that depends on the type of file-like object,
|
||||
* in the same way as {@link #setOut(PyObject)}.
|
||||
*
|
||||
* @param outStream Python file-like object to use as the error output stream
|
||||
*/
|
||||
public void setErr(PyObject outStream) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a {@link java.io.Writer} to use for the standard output stream, <code>sys.stdout</code>.
|
||||
* The behaviour as implemented is to output each object <code>o</code> by calling
|
||||
* <code>o.toString()</code> and writing this as UTF-16.
|
||||
*
|
||||
* @param outStream to use as the error output stream
|
||||
*/
|
||||
public void setErr(java.io.Writer outStream) {
|
||||
}
|
||||
|
||||
public void setErr(java.io.OutputStream outStream) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a string as a Python expression and returns the result.
|
||||
*/
|
||||
public PyObject eval(String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a Python code object and returns the result.
|
||||
*/
|
||||
public PyObject eval(PyObject code) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a string of Python source in the local namespace.
|
||||
*
|
||||
* In some environments, such as Windows, Unicode characters in the script will be converted
|
||||
* into ascii question marks (?). This can be avoided by first compiling the fragment using
|
||||
* PythonInterpreter.compile(), and using the overridden form of this method which takes a
|
||||
* PyCode object. Code page declarations are not supported.
|
||||
*/
|
||||
public void exec(String s) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a Python code object in the local namespace.
|
||||
*/
|
||||
public void exec(PyObject code) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a file of Python source in the local namespace.
|
||||
*/
|
||||
public void execfile(String filename) {
|
||||
}
|
||||
|
||||
public void execfile(java.io.InputStream s) {
|
||||
}
|
||||
|
||||
public void execfile(java.io.InputStream s, String name) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles a string of Python source as either an expression (if possible) or a module.
|
||||
*
|
||||
* Designed for use by a JSR 223 implementation: "the Scripting API does not distinguish between
|
||||
* scripts which return values and those which do not, nor do they make the corresponding
|
||||
* distinction between evaluating or executing objects." (SCR.4.2.1)
|
||||
*/
|
||||
public PyCode compile(String script) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PyCode compile(Reader reader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PyCode compile(String script, String filename) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PyCode compile(Reader reader, String filename) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a variable in the local namespace.
|
||||
*
|
||||
* @param name the name of the variable
|
||||
* @param value the object to set the variable to (as converted to an appropriate Python object)
|
||||
*/
|
||||
public void set(String name, Object value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a variable in the local namespace.
|
||||
*
|
||||
* @param name the name of the variable
|
||||
* @param value the Python object to set the variable to
|
||||
*/
|
||||
public void set(String name, PyObject value) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a variable in the local namespace.
|
||||
*
|
||||
* @param name the name of the variable
|
||||
* @return the value of the variable, or null if that name isn't assigned
|
||||
*/
|
||||
public PyObject get(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a variable in the local namespace.
|
||||
*
|
||||
* The value will be returned as an instance of the given Java class.
|
||||
* <code>interp.get("foo", Object.class)</code> will return the most appropriate generic Java
|
||||
* object.
|
||||
*
|
||||
* @param name the name of the variable
|
||||
* @param javaclass the class of object to return
|
||||
* @return the value of the variable as the given class, or null if that name isn't assigned
|
||||
*/
|
||||
public <T> T get(String name, Class<T> javaclass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.esotericsoftware.kryo.pool;
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
|
||||
public interface KryoCallback<T> {
|
||||
T execute (Kryo kryo);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.esotericsoftware.kryo.pool;
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
|
||||
public interface KryoFactory {
|
||||
Kryo create ();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.esotericsoftware.kryo.pool;
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
import java.util.Queue;
|
||||
|
||||
public interface KryoPool {
|
||||
|
||||
Kryo borrow ();
|
||||
|
||||
void release (Kryo kryo);
|
||||
|
||||
<T> T run (KryoCallback<T> callback);
|
||||
|
||||
static class Builder {
|
||||
public Builder (KryoFactory factory) {
|
||||
}
|
||||
|
||||
public Builder queue (Queue<Kryo> queue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Builder softReferences () {
|
||||
return null;
|
||||
}
|
||||
|
||||
public KryoPool build () {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
java/ql/test/stubs/scriptengine/javax/script/Bindings.java
Normal file
14
java/ql/test/stubs/scriptengine/javax/script/Bindings.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package javax.script;
|
||||
import java.util.Map;
|
||||
|
||||
public interface Bindings extends Map<String, Object> {
|
||||
public Object put(String name, Object value);
|
||||
|
||||
public void putAll(Map<? extends String, ? extends Object> toMerge);
|
||||
|
||||
public boolean containsKey(Object key);
|
||||
|
||||
public Object get(Object key);
|
||||
|
||||
public Object remove(Object key);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package javax.script;
|
||||
|
||||
import java.io.Reader;
|
||||
|
||||
public interface Compilable {
|
||||
public CompiledScript compile(String script) throws ScriptException;
|
||||
|
||||
public CompiledScript compile(Reader script) throws ScriptException;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package javax.script;
|
||||
|
||||
public abstract class CompiledScript {
|
||||
|
||||
public abstract Object eval(ScriptContext context) throws ScriptException;
|
||||
|
||||
public Object eval(Bindings bindings) throws ScriptException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object eval() throws ScriptException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract ScriptEngine getEngine();
|
||||
|
||||
}
|
||||
@@ -2,5 +2,7 @@ package javax.script;
|
||||
|
||||
public interface ScriptEngine {
|
||||
Object eval(String var1) throws ScriptException;
|
||||
|
||||
public ScriptEngineFactory getFactory();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package javax.script;
|
||||
|
||||
public interface ScriptEngineFactory {
|
||||
public String getEngineName();
|
||||
|
||||
public String getMethodCallSyntax(String obj, String m, String... args);
|
||||
|
||||
public String getProgram(String... statements);
|
||||
|
||||
ScriptEngine getScriptEngine();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package jdk.nashorn.api.scripting;
|
||||
|
||||
public interface ClassFilter {
|
||||
public boolean exposeToScripts(String className);
|
||||
}
|
||||
@@ -1,10 +1,31 @@
|
||||
package jdk.nashorn.api.scripting;
|
||||
|
||||
import javax.script.*;
|
||||
import java.io.Reader;
|
||||
|
||||
public final class NashornScriptEngine extends AbstractScriptEngine {
|
||||
import javax.script.AbstractScriptEngine;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable {
|
||||
public Object eval(String var1) throws ScriptException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngineFactory getFactory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompiledScript compile(final Reader reader) throws ScriptException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompiledScript compile(final String str) throws ScriptException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,48 @@ package jdk.nashorn.api.scripting;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
|
||||
|
||||
public final class NashornScriptEngineFactory implements ScriptEngineFactory {
|
||||
|
||||
public NashornScriptEngineFactory() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEngineName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodCallSyntax(final String obj, final String method, final String... args) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProgram(final String... statements) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptEngine getScriptEngine() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ScriptEngine getScriptEngine(final ClassLoader appLoader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ScriptEngine getScriptEngine(String... args) {
|
||||
public ScriptEngine getScriptEngine(final ClassFilter classFilter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ScriptEngine getScriptEngine(final String... args) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package org.springframework.web.servlet;
|
||||
|
||||
import java.util.Map;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
public class ModelAndView {
|
||||
@Nullable
|
||||
private Object view;
|
||||
@Nullable
|
||||
private HttpStatus status;
|
||||
private boolean cleared = false;
|
||||
|
||||
public ModelAndView() {
|
||||
}
|
||||
|
||||
public ModelAndView(String viewName) {
|
||||
this.view = viewName;
|
||||
}
|
||||
|
||||
public ModelAndView(View view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public ModelAndView(String viewName, @Nullable Map<String, ?> model) { }
|
||||
|
||||
public ModelAndView(View view, @Nullable Map<String, ?> model) { }
|
||||
|
||||
public ModelAndView(String viewName, HttpStatus status) { }
|
||||
|
||||
public ModelAndView(@Nullable String viewName, @Nullable Map<String, ?> model, @Nullable HttpStatus status) { }
|
||||
|
||||
public ModelAndView(String viewName, String modelName, Object modelObject) { }
|
||||
|
||||
public ModelAndView(View view, String modelName, Object modelObject) { }
|
||||
|
||||
public void setViewName(@Nullable String viewName) {
|
||||
this.view = viewName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getViewName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public void setView(@Nullable View view) { }
|
||||
|
||||
@Nullable
|
||||
public View getView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasView() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isReference() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Map<String, Object> getModelInternal() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<String, Object> getModel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setStatus(@Nullable HttpStatus status) { }
|
||||
|
||||
@Nullable
|
||||
public HttpStatus getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public ModelAndView addObject(String attributeName, @Nullable Object attributeValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ModelAndView addObject(Object attributeValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ModelAndView addAllObjects(@Nullable Map<String, ?> modelMap) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void clear() { }
|
||||
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean wasCleared() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "";
|
||||
}
|
||||
|
||||
private String formatView() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.springframework.web.servlet;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
public interface View {
|
||||
String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
|
||||
String PATH_VARIABLES = View.class.getName() + ".pathVariables";
|
||||
String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
|
||||
|
||||
@Nullable
|
||||
default String getContentType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
void render(@Nullable Map<String, ?> var1, HttpServletRequest var2, HttpServletResponse var3) throws Exception;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springframework.web.servlet.view;
|
||||
|
||||
import java.util.Locale;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
public abstract class AbstractUrlBasedView {
|
||||
@Nullable
|
||||
private String url;
|
||||
|
||||
protected AbstractUrlBasedView() { }
|
||||
|
||||
protected AbstractUrlBasedView(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public void setUrl(@Nullable String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getUrl() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception { }
|
||||
|
||||
protected boolean isUrlRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkResource(Locale locale) throws Exception {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
package org.springframework.web.servlet.view;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
public class RedirectView extends AbstractUrlBasedView {
|
||||
private static final Pattern URI_TEMPLATE_VARIABLE_PATTERN = Pattern.compile("\\{([^/]+?)\\}");
|
||||
private boolean contextRelative = false;
|
||||
private boolean http10Compatible = true;
|
||||
private boolean exposeModelAttributes = true;
|
||||
@Nullable
|
||||
private String encodingScheme;
|
||||
@Nullable
|
||||
private HttpStatus statusCode;
|
||||
private boolean expandUriTemplateVariables = true;
|
||||
private boolean propagateQueryParams = false;
|
||||
@Nullable
|
||||
private String[] hosts;
|
||||
|
||||
public RedirectView() { }
|
||||
|
||||
public RedirectView(String url) { }
|
||||
|
||||
public RedirectView(String url, boolean contextRelative) { }
|
||||
|
||||
public RedirectView(String url, boolean contextRelative, boolean http10Compatible) { }
|
||||
|
||||
public RedirectView(String url, boolean contextRelative, boolean http10Compatible, boolean exposeModelAttributes) { }
|
||||
|
||||
public void setContextRelative(boolean contextRelative) { }
|
||||
|
||||
public void setHttp10Compatible(boolean http10Compatible) { }
|
||||
|
||||
public void setExposeModelAttributes(boolean exposeModelAttributes) { }
|
||||
|
||||
public void setEncodingScheme(String encodingScheme) { }
|
||||
|
||||
public void setStatusCode(HttpStatus statusCode) { }
|
||||
|
||||
public void setExpandUriTemplateVariables(boolean expandUriTemplateVariables) { }
|
||||
|
||||
public void setPropagateQueryParams(boolean propagateQueryParams) { }
|
||||
|
||||
public boolean isPropagateQueryProperties() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setHosts(@Nullable String... hosts) { }
|
||||
|
||||
@Nullable
|
||||
public String[] getHosts() {
|
||||
return this.hosts;
|
||||
}
|
||||
|
||||
public boolean isRedirectView() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isContextRequired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws IOException { }
|
||||
|
||||
protected final String createTargetUrl(Map<String, Object> model, HttpServletRequest request) throws UnsupportedEncodingException {
|
||||
return "";
|
||||
}
|
||||
|
||||
private String getContextPath(HttpServletRequest request) {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected StringBuilder replaceUriTemplateVariables(String targetUrl, Map<String, Object> model, Map<String, String> currentUriVariables, String encodingScheme) throws UnsupportedEncodingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Map<String, String> getCurrentRequestUriVariables(HttpServletRequest request) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void appendCurrentQueryParams(StringBuilder targetUrl, HttpServletRequest request) { }
|
||||
|
||||
protected void appendQueryProperties(StringBuilder targetUrl, Map<String, Object> model, String encodingScheme) throws UnsupportedEncodingException { }
|
||||
|
||||
protected Map<String, Object> queryProperties(Map<String, Object> model) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean isEligibleProperty(String key, @Nullable Object value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isEligibleValue(@Nullable Object value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected String urlEncode(String input, String encodingScheme) throws UnsupportedEncodingException {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected String updateTargetUrl(String targetUrl, Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
|
||||
return "";
|
||||
}
|
||||
|
||||
protected void sendRedirect(HttpServletRequest request, HttpServletResponse response, String targetUrl, boolean http10Compatible) throws IOException { }
|
||||
|
||||
protected boolean isRemoteHost(String targetUrl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected HttpStatus getHttp11StatusCode(HttpServletRequest request, HttpServletResponse response, String targetUrl) {
|
||||
return this.statusCode;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user