Merge branch 'main' into atorralba/promote-ognl-injection

This commit is contained in:
Tony Torralba
2021-05-19 10:41:08 +02:00
198 changed files with 13516 additions and 3965 deletions

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* Increase coverage of dataflow through Jackson JSON deserialized objects.

View 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)

View 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.

View File

@@ -6,6 +6,7 @@
* or comments.
* @kind metric
* @tags summary
* lines-of-code
*/
import java

View File

@@ -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();
}
}
}
}

View File

@@ -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>

View 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"

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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"

View File

@@ -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>

View 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"

View File

@@ -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;
}
}

View File

@@ -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>

View File

@@ -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"

View File

@@ -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()
)
)
}
}

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 }
}

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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")
}
}

View File

@@ -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"
]
}
}

View File

@@ -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) {

View File

@@ -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")
)
}
}

View File

@@ -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 |

View File

@@ -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();
}
}
}
}

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-094/JythonInjection.ql

View File

@@ -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());
}
}

View File

@@ -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 |

View File

@@ -1 +0,0 @@
experimental/Security/CWE/CWE-094/ScriptEngine.ql

View File

@@ -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());
}
}
}

View File

@@ -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 |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-094/ScriptInjection.ql

View File

@@ -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

View File

@@ -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 |

View File

@@ -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);
}
}

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-601/SpringUrlRedirect.ql

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/springframework-5.2.3/

View File

@@ -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);
}

View File

@@ -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() {
}
}

View File

@@ -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;
}
}

View File

@@ -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 &gt; 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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
{
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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
{
}

View File

@@ -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;
}
}

View File

@@ -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
}
}

View File

@@ -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 |

View File

@@ -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 = ""
)
}
}

View 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);
}
}
}

View File

@@ -1,6 +1,8 @@
package com.fasterxml.jackson.databind;
public class JsonNode {
import java.util.*;
public abstract class JsonNode implements Iterable<JsonNode> {
public JsonNode() {
}
}
}

View File

@@ -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 {
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,5 @@
// Autogenerated AST node
package org.python.antlr.base;
public abstract class mod {
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,11 @@
package org.python.core;
public enum CompileMode {
eval,
single,
exec;
public static CompileMode getMode(String mode) {
return null;
}
}

View File

@@ -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) {
}
}

View 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;
}
}

View 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);
}

View File

@@ -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
{
}

View File

@@ -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 {
}

View File

@@ -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() {
}
}

View File

@@ -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) {
}
}

View File

@@ -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() {
}
}

View File

@@ -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() {
}
}

View File

@@ -0,0 +1,7 @@
package com.esotericsoftware.kryo.pool;
import com.esotericsoftware.kryo.Kryo;
public interface KryoCallback<T> {
T execute (Kryo kryo);
}

View File

@@ -0,0 +1,7 @@
package com.esotericsoftware.kryo.pool;
import com.esotericsoftware.kryo.Kryo;
public interface KryoFactory {
Kryo create ();
}

View File

@@ -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;
}
}
}

View 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);
}

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -2,5 +2,7 @@ package javax.script;
public interface ScriptEngine {
Object eval(String var1) throws ScriptException;
public ScriptEngineFactory getFactory();
}

View File

@@ -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();
}

View File

@@ -0,0 +1,5 @@
package jdk.nashorn.api.scripting;
public interface ClassFilter {
public boolean exposeToScripts(String className);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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 "";
}
}

View File

@@ -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;
}

View File

@@ -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 "";
}
}

View File

@@ -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;
}
}