Merge branch 'master' of github.com:github/codeql into SharedDataflow

to receive updates from data flow library
This commit is contained in:
Rasmus Lerchedahl Petersen
2020-07-01 07:15:32 +02:00
275 changed files with 16386 additions and 1912 deletions

View File

@@ -1,3 +1,5 @@
/** INTERNAL - Methods used by queries that test whether functions are invoked correctly. */
import python
import Testing.Mox
@@ -71,36 +73,38 @@ private int positional_arg_count_for_call(Call call, Value callable) {
)
}
/** Gets the number of arguments in `call`. */
int arg_count_objectapi(Call call) {
result = count(call.getAnArg()) + varargs_length_objectapi(call) + count(call.getAKeyword())
}
/** Gets the number of arguments in `call`. */
int arg_count(Call call) {
result = count(call.getAnArg()) + varargs_length(call) + count(call.getAKeyword())
}
/* Gets a call corresponding to the given class or function*/
/** Gets a call corresponding to the given class or function. */
private ControlFlowNode get_a_call_objectapi(Object callable) {
result = callable.(ClassObject).getACall()
or
result = callable.(FunctionObject).getACall()
}
/* Gets a call corresponding to the given class or function*/
/** Gets a call corresponding to the given class or function. */
private ControlFlowNode get_a_call(Value callable) {
result = callable.(ClassValue).getACall()
or
result = callable.(FunctionValue).getACall()
}
/* Gets the function object corresponding to the given class or function*/
/** Gets the function object corresponding to the given class or function. */
FunctionObject get_function_or_initializer_objectapi(Object func_or_cls) {
result = func_or_cls.(FunctionObject)
or
result = func_or_cls.(ClassObject).declaredAttribute("__init__")
}
/* Gets the function object corresponding to the given class or function*/
/** Gets the function object corresponding to the given class or function. */
FunctionValue get_function_or_initializer(Value func_or_cls) {
result = func_or_cls.(FunctionValue)
or

View File

@@ -1,5 +1,6 @@
import python
/** A string constant that looks like it may be used in string formatting operations. */
library class PossibleAdvancedFormatString extends StrConst {
PossibleAdvancedFormatString() { this.getText().matches("%{%}%") }
@@ -51,6 +52,7 @@ library class PossibleAdvancedFormatString extends StrConst {
predicate isExplicitlyNumbered() { exists(this.fieldId(_, _).toInt()) }
}
/** Holds if the formatting string `fmt` contains a sequence of braces `{` of length `len`, beginning at index `index`. */
predicate brace_sequence(PossibleAdvancedFormatString fmt, int index, int len) {
exists(string text | text = fmt.getText() |
text.charAt(index) = "{" and not text.charAt(index - 1) = "{" and len = 1
@@ -61,10 +63,12 @@ predicate brace_sequence(PossibleAdvancedFormatString fmt, int index, int len) {
)
}
/** Holds if index `index` in the format string `fmt` contains an escaped brace `{`. */
predicate escaped_brace(PossibleAdvancedFormatString fmt, int index) {
exists(int len | brace_sequence(fmt, index, len) | len % 2 = 0)
}
/** Holds if index `index` in the format string `fmt` contains a left brace `{` that acts as an escape character. */
predicate escaping_brace(PossibleAdvancedFormatString fmt, int index) {
escaped_brace(fmt, index + 1)
}
@@ -105,15 +109,18 @@ private predicate advanced_format_call(Call format_expr, PossibleAdvancedFormatS
)
}
/** A string constant that has the `format` method applied to it. */
class AdvancedFormatString extends PossibleAdvancedFormatString {
AdvancedFormatString() { advanced_format_call(_, this, _) }
}
/** A string formatting operation that uses the `format` method. */
class AdvancedFormattingCall extends Call {
AdvancedFormattingCall() { advanced_format_call(this, _, _) }
/** Count of the arguments actually provided */
int providedArgCount() { advanced_format_call(this, _, result) }
/** Gets a formatting string for this call. */
AdvancedFormatString getAFormat() { advanced_format_call(this, result, _) }
}

View File

@@ -1,5 +1,8 @@
/** INTERNAL - Helper predicates for queries that inspect the comparison of objects using `is`. */
import python
/** Holds if the comparison `comp` uses `is` or `is not` (represented as `op`) to compare its `left` and `right` arguments. */
predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, ControlFlowNode right) {
exists(CompareNode fcomp | fcomp = comp.getAFlowNode() |
fcomp.operands(left, op, right) and
@@ -7,6 +10,7 @@ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, Cont
)
}
/** Holds if the class `c` overrides the default notion of equality or comparison. */
predicate overrides_eq_or_cmp(ClassValue c) {
major_version() = 2 and c.hasAttribute("__eq__")
or
@@ -19,12 +23,14 @@ predicate overrides_eq_or_cmp(ClassValue c) {
major_version() = 2 and c.hasAttribute("__cmp__")
}
/** Holds if the class `cls` is likely to only have a single instance throughout the program. */
predicate probablySingleton(ClassValue cls) {
strictcount(Value inst | inst.getClass() = cls) = 1
or
cls = Value::named("None").getClass()
}
/** Holds if using `is` to compare instances of the class `c` is likely to cause unexpected behavior. */
predicate invalid_to_use_is_portably(ClassValue c) {
overrides_eq_or_cmp(c) and
// Exclude type/builtin-function/bool as it is legitimate to compare them using 'is' but they implement __eq__
@@ -35,6 +41,7 @@ predicate invalid_to_use_is_portably(ClassValue c) {
not probablySingleton(c)
}
/** Holds if the control flow node `f` points to either `True`, `False`, or `None`. */
predicate simple_constant(ControlFlowNode f) {
exists(Value val | f.pointsTo(val) |
val = Value::named("True") or val = Value::named("False") or val = Value::named("None")
@@ -66,10 +73,12 @@ private predicate universally_interned_value(Expr e) {
e.(StrConst).getText() = ""
}
/** Holds if the expression `e` points to an interned constant in CPython. */
predicate cpython_interned_constant(Expr e) {
exists(Expr const | e.pointsTo(_, const) | cpython_interned_value(const))
}
/** Holds if the expression `e` points to a value that can be reasonably expected to be interned across all implementations of Python. */
predicate universally_interned_constant(Expr e) {
exists(Expr const | e.pointsTo(_, const) | universally_interned_value(const))
}
@@ -92,6 +101,9 @@ private predicate comparison_one_type(Compare comp, Cmpop op, ClassValue cls) {
)
}
/**
* Holds if using `is` or `is not` as the operator `op` in the comparison `comp` would be invalid when applied to the class `cls`.
*/
predicate invalid_portable_is_comparison(Compare comp, Cmpop op, ClassValue cls) {
// OK to use 'is' when defining '__eq__'
not exists(Function eq | eq.getName() = "__eq__" or eq.getName() = "__ne__" |

View File

@@ -1,5 +1,8 @@
/** Helper functions for queries that test redundant comparisons. */
import python
/** A comparison where the left and right hand sides appear to be identical. */
class RedundantComparison extends Compare {
RedundantComparison() {
exists(Expr left, Expr right |
@@ -8,6 +11,15 @@ class RedundantComparison extends Compare {
)
}
/** Holds if this comparison could be redundant due to a missing `self.`, for example
* ```python
* foo == foo
* ```
* instead of
* ```python
* self.foo == foo
* ```
*/
predicate maybeMissingSelf() {
exists(Name left |
this.compares(left, _, _) and

View File

@@ -175,6 +175,7 @@ class CommentedOutCodeLine extends Comment {
class CommentedOutCodeBlock extends @py_comment {
CommentedOutCodeBlock() { commented_out_code_block(this, _) }
/** Gets a textual representation of this element. */
string toString() { result = "Commented out code" }
/** Whether this commented-out code block contains the comment c */
@@ -191,10 +192,19 @@ class CommentedOutCodeBlock extends @py_comment {
/** The length of this comment block (in comments) */
int length() { result = count(Comment c | this.contains(c)) }
predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) {
this.(Comment).getLocation().hasLocationInfo(filepath, bl, bc, _, _) and
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.(Comment).getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
exists(Comment end | commented_out_code_block(this, end) |
end.getLocation().hasLocationInfo(_, _, _, el, ec)
end.getLocation().hasLocationInfo(_, _, _, endline, endcolumn)
)
}

View File

@@ -15,9 +15,17 @@ import python
* including the body (if any), as opposed to the location of its name only.
*/
class RangeFunction extends Function {
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
super.getLocation().hasLocationInfo(path, sl, sc, _, _) and
this.getBody().getLastItem().getLocation().hasLocationInfo(path, _, _, el, ec)
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) { super.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
this.getBody().getLastItem().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn)
}
}
@@ -26,8 +34,16 @@ class RangeFunction extends Function {
* including the body (if any), as opposed to the location of its name only.
*/
class RangeClass extends Class {
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
super.getLocation().hasLocationInfo(path, sl, sc, _, _) and
this.getBody().getLastItem().getLocation().hasLocationInfo(path, _, _, el, ec)
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) { super.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
this.getBody().getLastItem().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn)
}
}

View File

@@ -1,3 +1,5 @@
/** Contains predicates concerning when and where files are opened and closed. */
import python
import semmle.python.GuardedControlFlow
import semmle.python.pointsto.Filters
@@ -113,12 +115,14 @@ predicate close_method_call(CallNode call, ControlFlowNode self) {
call.getFunction().(AttrNode).getObject("close") = self
}
/** Holds if `close` is a function that appears to close files that are passed to it as an argument. */
predicate function_closes_file(FunctionValue close) {
close = Value::named("os.close")
or
function_should_close_parameter(close.getScope())
}
/** INTERNAL - Helper predicate for `function_closes_file` */
predicate function_should_close_parameter(Function func) {
exists(EssaDefinition def |
closes_file(def) and
@@ -126,6 +130,7 @@ predicate function_should_close_parameter(Function func) {
)
}
/** Holds if the function `f` opens a file, either directly or indirectly. */
predicate function_opens_file(FunctionValue f) {
f = Value::named("open")
or
@@ -140,6 +145,7 @@ predicate function_opens_file(FunctionValue f) {
)
}
/** Holds if the variable `v` refers to a file opened at `open` which is subsequently returned from a function. */
predicate file_is_returned(EssaVariable v, ControlFlowNode open) {
exists(NameNode n, Return ret |
var_is_open(v, open) and

View File

@@ -10,6 +10,7 @@ private newtype TDefinition =
/** A definition for the purposes of jump-to-definition. */
class Definition extends TLocalDefinition {
/** Gets a textual representation of this element. */
string toString() { result = "Definition " + this.getAstNode().getLocation().toString() }
AstNode getAstNode() { this = TLocalDefinition(result) }
@@ -467,8 +468,15 @@ Definition getUniqueDefinition(Expr use) {
/** Helper class to get suitable locations for attributes */
class NiceLocationExpr extends @py_expr {
/** Gets a textual representation of this element. */
string toString() { result = this.(Expr).toString() }
/**
* Holds if this element is at the specified location.
* The location spans column `bc` of line `bl` to
* column `ec` of line `el` in file `f`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(string f, int bl, int bc, int el, int ec) {
/* Attribute location for x.y is that of 'y' so that url does not overlap with that of 'x' */
exists(int abl, int abc | this.(Attribute).getLocation().hasLocationInfo(f, abl, abc, el, ec) |

View File

@@ -0,0 +1,18 @@
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
<qhelp>
<overview>
<p>
Processing an unvalidated XSL stylesheet can allow an attacker to change the structure and contents of the resultant XML, include arbitrary files from the file system, or execute arbitrary code.
</p>
</overview>
<recommendation>
<p>
This vulnerability can be prevented by not allowing untrusted user input to be passed as an XSL stylesheet.
If the application logic necessiates processing untrusted XSL stylesheets, the input should be properly filtered and sanitized before use.
</p>
</recommendation>
<example>
<p>In the example below, the XSL stylesheet is controlled by the user and hence leads to a vulnerability.</p>
<sample src="xslt.py" />
</example>
</qhelp>

View File

@@ -0,0 +1,35 @@
/**
* @name XSLT query built from user-controlled sources
* @description Building a XSLT query from user-controlled sources is vulnerable to insertion of
* malicious XSLT code by the user.
* @kind path-problem
* @problem.severity error
* @precision high
* @id py/xslt-injection
* @tags security
* external/cwe/cwe-643
*/
import python
import semmle.python.security.Paths
/* Sources */
import semmle.python.web.HttpRequest
/* Sinks */
import experimental.semmle.python.security.injection.XSLT
class XSLTInjectionConfiguration extends TaintTracking::Configuration {
XSLTInjectionConfiguration() { this = "XSLT injection configuration" }
override predicate isSource(TaintTracking::Source source) {
source instanceof HttpRequestTaintSource
}
override predicate isSink(TaintTracking::Sink sink) {
sink instanceof XSLTInjection::XSLTInjectionSink
}
}
from XSLTInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink
where config.hasFlowPath(src, sink)
select sink.getSink(), src, sink, "This XSLT query depends on $@.", src.getSource(),
"a user-provided value"

View File

@@ -0,0 +1,14 @@
from lxml import etree
from io import StringIO
from flask import Flask, request
app = Flask(__name__)
@app.route("/xslt")
def bad():
xsltQuery = request.args.get('xml', '')
xslt_root = etree.XML(xsltQuery)
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result_tree = tree.xslt(xslt_root) # Not OK

View File

@@ -0,0 +1,115 @@
/**
* Provides class and predicates to track external data that
* may represent malicious XSLT query objects.
*
* This module is intended to be imported into a taint-tracking query
* to extend `TaintKind` and `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.web.HttpRequest
/** Models XSLT Injection related classes and functions */
module XSLTInjection {
/** Returns a class value which refers to `lxml.etree` */
Value etree() { result = Value::named("lxml.etree") }
/** A generic taint sink that is vulnerable to XSLT injection. */
abstract class XSLTInjectionSink extends TaintSink { }
/**
* A kind of "taint", representing an untrusted XML string
*/
private class ExternalXmlStringKind extends ExternalStringKind {
ExternalXmlStringKind() { this = "etree.XML string" }
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
etreeXML(fromnode, tonode) and result instanceof ExternalXmlKind
or
etreeFromStringList(fromnode, tonode) and result instanceof ExternalXmlKind
or
etreeFromString(fromnode, tonode) and result instanceof ExternalXmlKind
}
}
/**
* A kind of "taint", representing a XML encoded string
*/
class ExternalXmlKind extends TaintKind {
ExternalXmlKind() { this = "lxml etree xml" }
}
private predicate etreeXML(ControlFlowNode fromnode, CallNode tonode) {
// etree.XML("<xmlContent>")
exists(CallNode call | call.getFunction().(AttrNode).getObject("XML").pointsTo(etree()) |
call.getArg(0) = fromnode and
call = tonode
)
}
private predicate etreeFromString(ControlFlowNode fromnode, CallNode tonode) {
// etree.fromstring(text, parser=None)
exists(CallNode call | call.getFunction().(AttrNode).getObject("fromstring").pointsTo(etree()) |
call.getArg(0) = fromnode and
call = tonode
)
}
private predicate etreeFromStringList(ControlFlowNode fromnode, CallNode tonode) {
// etree.fromstringlist(strings, parser=None)
exists(CallNode call |
call.getFunction().(AttrNode).getObject("fromstringlist").pointsTo(etree())
|
call.getArg(0) = fromnode and
call = tonode
)
}
/**
* A Sink representing an argument to the `etree.XSLT` call.
*
* from lxml import etree
* root = etree.XML("<xmlContent>")
* find_text = etree.XSLT("`sink`")
*/
private class EtreeXSLTArgument extends XSLTInjectionSink {
override string toString() { result = "lxml.etree.XSLT" }
EtreeXSLTArgument() {
exists(CallNode call | call.getFunction().(AttrNode).getObject("XSLT").pointsTo(etree()) |
call.getArg(0) = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalXmlKind }
}
/**
* A Sink representing an argument to the `XSLT` call to a parsed xml document.
*
* from lxml import etree
* from io import StringIO
* `sink` = etree.XML(xsltQuery)
* tree = etree.parse(f)
* result_tree = tree.xslt(`sink`)
*/
private class ParseXSLTArgument extends XSLTInjectionSink {
override string toString() { result = "lxml.etree.parse.xslt" }
ParseXSLTArgument() {
exists(
CallNode parseCall, CallNode xsltCall, ControlFlowNode obj, Variable var, AssignStmt assign
|
parseCall.getFunction().(AttrNode).getObject("parse").pointsTo(etree()) and
assign.getValue().(Call).getAFlowNode() = parseCall and
xsltCall.getFunction().(AttrNode).getObject("xslt") = obj and
var.getAUse() = obj and
assign.getATarget() = var.getAStore() and
xsltCall.getArg(0) = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalXmlKind }
}
}

View File

@@ -26,7 +26,9 @@ class DefectResult extends int {
/** Gets the file in which this query result was reported. */
File getFile() {
exists(string path | defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path)
exists(string path |
defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path
)
}
/** Gets the file path in which this query result was reported. */
@@ -47,8 +49,17 @@ class DefectResult extends int {
/** Gets the message associated with this query result. */
string getMessage() { defectResults(this, _, _, _, _, _, _, result) }
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
defectResults(this, _, path, sl, sc, el, ec, _)
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
defectResults(this, _, filepath, startline, startcolumn, endline, endcolumn, _)
}
/** Gets the URL corresponding to the location of this query result. */

View File

@@ -1,3 +1,7 @@
/**
* Provides classes for working with external data.
*/
import python
class ExternalDefect extends @externalDefect {
@@ -14,6 +18,7 @@ class ExternalDefect extends @externalDefect {
Location getLocation() { externalDefects(this, _, result, _, _) }
/** Gets a textual representation of this element. */
string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getMessage() }
}
@@ -24,26 +29,42 @@ class ExternalMetric extends @externalMetric {
Location getLocation() { externalMetrics(this, _, result, _) }
/** Gets a textual representation of this element. */
string toString() { result = getQueryPath() + ": " + getLocation() + " - " + getValue() }
}
/**
* An external data item.
*/
class ExternalData extends @externalDataElement {
/** Gets the path of the file this data was loaded from. */
string getDataPath() { externalData(this, result, _, _) }
/**
* Gets the path of the file this data was loaded from, with its
* extension replaced by `.ql`.
*/
string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") }
/** Gets the number of fields in this data item. */
int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) }
/** Gets the value of the field at position `index` of this data item. */
string getField(int index) { externalData(this, _, index, result) }
/** Gets the integer value of the field at position `index` of this data item. */
int getFieldAsInt(int index) { result = getField(index).toInt() }
/** Gets the floating-point value of the field at position `index` of this data item. */
float getFieldAsFloat(int index) { result = getField(index).toFloat() }
/** Gets the value of the field at position `index` of this data item, interpreted as a date. */
date getFieldAsDate(int index) { result = getField(index).toDate() }
/** Gets a textual representation of this data item. */
string toString() { result = getQueryPath() + ": " + buildTupleString(0) }
/** Gets a textual representation of this data item, starting with the field at position `start`. */
private string buildTupleString(int start) {
start = getNumFields() - 1 and result = getField(start)
or

View File

@@ -33,18 +33,27 @@ class ThriftElement extends ExternalData {
private int column() { result = this.getFieldAsInt(6) }
predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) {
fp = this.getPath() and
bl = this.line() and
bc = this.column() and
el = this.line() and
ec = this.column() + this.getValue().length() - 1
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
filepath = this.getPath() and
startline = this.line() and
startcolumn = this.column() and
endline = this.line() and
endcolumn = this.column() + this.getValue().length() - 1
or
exists(ThriftElement first, ThriftElement last |
first = this.getChild(min(int l | exists(this.getChild(l)))) and
last = this.getChild(max(int l | exists(this.getChild(l)))) and
first.hasLocationInfo(fp, bl, bc, _, _) and
last.hasLocationInfo(fp, _, _, el, ec)
first.hasLocationInfo(filepath, startline, startcolumn, _, _) and
last.hasLocationInfo(filepath, _, _, endline, endcolumn)
)
}
@@ -62,11 +71,11 @@ abstract class ThriftNamedElement extends ThriftElement {
not exists(this.getName()) and result = this.getKind() + " ???"
}
override predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) {
override predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
exists(ThriftElement first |
first = this.getChild(min(int l | exists(this.getChild(l)))) and
first.hasLocationInfo(fp, bl, bc, _, _) and
this.getNameElement().hasLocationInfo(fp, _, _, el, ec)
first.hasLocationInfo(filepath, startline, startcolumn, _, _) and
this.getNameElement().hasLocationInfo(filepath, _, _, endline, endcolumn)
)
}
}
@@ -142,9 +151,9 @@ class ThriftFunction extends ThriftNamedElement {
ThriftType getReturnType() { result = this.getChild(1).getChild(0) }
override predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) {
this.getChild(1).hasLocationInfo(fp, bl, bc, _, _) and
this.getChild(2).hasLocationInfo(fp, _, _, el, ec)
override predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
this.getChild(1).hasLocationInfo(filepath, startline, startcolumn, _, _) and
this.getChild(2).hasLocationInfo(filepath, _, _, endline, endcolumn)
}
ThriftService getService() { result.getAFunction() = this }

View File

@@ -10,6 +10,7 @@ class Commit extends @svnentry {
)
}
/** Gets a textual representation of this element. */
string toString() { result = this.getRevisionName() }
string getRevisionName() { svnentries(this, result, _, _, _) }

View File

@@ -1,4 +1,4 @@
/*
/**
* This library file is auto-generated by 'semmle/query_gen.py'.
* WARNING: Any modifications to this file will be lost.
* Relations can be changed by modifying master.py.
@@ -6,14 +6,17 @@
import python
/** INTERNAL: See the class `Add` for further information. */
library class Add_ extends @py_Add, Operator {
override string toString() { result = "Add" }
}
/** INTERNAL: See the class `And` for further information. */
library class And_ extends @py_And, Boolop {
override string toString() { result = "And" }
}
/** INTERNAL: See the class `AnnAssign` for further information. */
library class AnnAssign_ extends @py_AnnAssign, Stmt {
/** Gets the value of this annotated assignment. */
Expr getValue() { py_exprs(result, _, this, 1) }
@@ -27,6 +30,7 @@ library class AnnAssign_ extends @py_AnnAssign, Stmt {
override string toString() { result = "AnnAssign" }
}
/** INTERNAL: See the class `Assert` for further information. */
library class Assert_ extends @py_Assert, Stmt {
/** Gets the value being tested of this assert statement. */
Expr getTest() { py_exprs(result, _, this, 1) }
@@ -37,6 +41,7 @@ library class Assert_ extends @py_Assert, Stmt {
override string toString() { result = "Assert" }
}
/** INTERNAL: See the class `Assign` for further information. */
library class Assign_ extends @py_Assign, Stmt {
/** Gets the value of this assignment statement. */
Expr getValue() { py_exprs(result, _, this, 1) }
@@ -53,6 +58,7 @@ library class Assign_ extends @py_Assign, Stmt {
override string toString() { result = "Assign" }
}
/** INTERNAL: See the class `AssignExpr` for further information. */
library class AssignExpr_ extends @py_AssignExpr, Expr {
/** Gets the value of this assignment expression. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -63,6 +69,7 @@ library class AssignExpr_ extends @py_AssignExpr, Expr {
override string toString() { result = "AssignExpr" }
}
/** INTERNAL: See the class `Attribute` for further information. */
library class Attribute_ extends @py_Attribute, Expr {
/** Gets the object of this attribute expression. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -76,6 +83,7 @@ library class Attribute_ extends @py_Attribute, Expr {
override string toString() { result = "Attribute" }
}
/** INTERNAL: See the class `AugAssign` for further information. */
library class AugAssign_ extends @py_AugAssign, Stmt {
/** Gets the operation of this augmented assignment statement. */
BinaryExpr getOperation() { py_exprs(result, _, this, 1) }
@@ -83,14 +91,17 @@ library class AugAssign_ extends @py_AugAssign, Stmt {
override string toString() { result = "AugAssign" }
}
/** INTERNAL: See the class `AugLoad` for further information. */
library class AugLoad_ extends @py_AugLoad, ExprContext {
override string toString() { result = "AugLoad" }
}
/** INTERNAL: See the class `AugStore` for further information. */
library class AugStore_ extends @py_AugStore, ExprContext {
override string toString() { result = "AugStore" }
}
/** INTERNAL: See the class `Await` for further information. */
library class Await_ extends @py_Await, Expr {
/** Gets the expression waited upon of this await expression. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -98,6 +109,7 @@ library class Await_ extends @py_Await, Expr {
override string toString() { result = "Await" }
}
/** INTERNAL: See the class `BinaryExpr` for further information. */
library class BinaryExpr_ extends @py_BinaryExpr, Expr {
/** Gets the left sub-expression of this binary expression. */
Expr getLeft() { py_exprs(result, _, this, 2) }
@@ -113,18 +125,22 @@ library class BinaryExpr_ extends @py_BinaryExpr, Expr {
override string toString() { result = "BinaryExpr" }
}
/** INTERNAL: See the class `BitAnd` for further information. */
library class BitAnd_ extends @py_BitAnd, Operator {
override string toString() { result = "BitAnd" }
}
/** INTERNAL: See the class `BitOr` for further information. */
library class BitOr_ extends @py_BitOr, Operator {
override string toString() { result = "BitOr" }
}
/** INTERNAL: See the class `BitXor` for further information. */
library class BitXor_ extends @py_BitXor, Operator {
override string toString() { result = "BitXor" }
}
/** INTERNAL: See the class `BoolExpr` for further information. */
library class BoolExpr_ extends @py_BoolExpr, Expr {
/** Gets the operator of this boolean expression. */
Boolop getOp() { py_boolops(result, _, this) }
@@ -141,10 +157,12 @@ library class BoolExpr_ extends @py_BoolExpr, Expr {
override string toString() { result = "BoolExpr" }
}
/** INTERNAL: See the class `Break` for further information. */
library class Break_ extends @py_Break, Stmt {
override string toString() { result = "Break" }
}
/** INTERNAL: See the class `Bytes` for further information. */
library class Bytes_ extends @py_Bytes, Expr {
/** Gets the value of this bytes expression. */
string getS() { py_bytes(result, this, 2) }
@@ -168,10 +186,13 @@ library class Bytes_ extends @py_Bytes, Expr {
override string toString() { result = "Bytes" }
}
/** INTERNAL: See the class `BytesOrStr` for further information. */
library class BytesOrStr_ extends @py_Bytes_or_Str {
/** Gets a textual representation of this element. */
string toString() { result = "BytesOrStr" }
}
/** INTERNAL: See the class `Call` for further information. */
library class Call_ extends @py_Call, Expr {
/** Gets the callable of this call expression. */
Expr getFunc() { py_exprs(result, _, this, 2) }
@@ -197,6 +218,7 @@ library class Call_ extends @py_Call, Expr {
override string toString() { result = "Call" }
}
/** INTERNAL: See the class `Class` for further information. */
library class Class_ extends @py_Class {
/** Gets the name of this class. */
string getName() { py_strs(result, this, 0) }
@@ -212,9 +234,11 @@ library class Class_ extends @py_Class {
ClassExpr getParent() { py_Classes(this, result) }
/** Gets a textual representation of this element. */
string toString() { result = "Class" }
}
/** INTERNAL: See the class `ClassExpr` for further information. */
library class ClassExpr_ extends @py_ClassExpr, Expr {
/** Gets the name of this class definition. */
string getName() { py_strs(result, this, 2) }
@@ -243,6 +267,7 @@ library class ClassExpr_ extends @py_ClassExpr, Expr {
override string toString() { result = "ClassExpr" }
}
/** INTERNAL: See the class `Compare` for further information. */
library class Compare_ extends @py_Compare, Expr {
/** Gets the left sub-expression of this compare expression. */
Expr getLeft() { py_exprs(result, _, this, 2) }
@@ -268,14 +293,17 @@ library class Compare_ extends @py_Compare, Expr {
override string toString() { result = "Compare" }
}
/** INTERNAL: See the class `Continue` for further information. */
library class Continue_ extends @py_Continue, Stmt {
override string toString() { result = "Continue" }
}
/** INTERNAL: See the class `Del` for further information. */
library class Del_ extends @py_Del, ExprContext {
override string toString() { result = "Del" }
}
/** INTERNAL: See the class `Delete` for further information. */
library class Delete_ extends @py_Delete, Stmt {
/** Gets the targets of this delete statement. */
ExprList getTargets() { py_expr_lists(result, this, 1) }
@@ -289,6 +317,7 @@ library class Delete_ extends @py_Delete, Stmt {
override string toString() { result = "Delete" }
}
/** INTERNAL: See the class `Dict` for further information. */
library class Dict_ extends @py_Dict, Expr {
/** Gets the items of this dictionary expression. */
DictItemList getItems() { py_dict_item_lists(result, this) }
@@ -302,6 +331,7 @@ library class Dict_ extends @py_Dict, Expr {
override string toString() { result = "Dict" }
}
/** INTERNAL: See the class `DictComp` for further information. */
library class DictComp_ extends @py_DictComp, Expr {
/** Gets the implementation of this dictionary comprehension. */
Function getFunction() { py_Functions(result, this) }
@@ -312,6 +342,7 @@ library class DictComp_ extends @py_DictComp, Expr {
override string toString() { result = "DictComp" }
}
/** INTERNAL: See the class `DictUnpacking` for further information. */
library class DictUnpacking_ extends @py_DictUnpacking, DictItem {
/** Gets the location of this dictionary unpacking. */
override Location getLocation() { py_locations(result, this) }
@@ -322,18 +353,22 @@ library class DictUnpacking_ extends @py_DictUnpacking, DictItem {
override string toString() { result = "DictUnpacking" }
}
/** INTERNAL: See the class `Div` for further information. */
library class Div_ extends @py_Div, Operator {
override string toString() { result = "Div" }
}
/** INTERNAL: See the class `Ellipsis` for further information. */
library class Ellipsis_ extends @py_Ellipsis, Expr {
override string toString() { result = "Ellipsis" }
}
/** INTERNAL: See the class `Eq` for further information. */
library class Eq_ extends @py_Eq, Cmpop {
override string toString() { result = "Eq" }
}
/** INTERNAL: See the class `ExceptStmt` for further information. */
library class ExceptStmt_ extends @py_ExceptStmt, Stmt {
/** Gets the type of this except block. */
Expr getType() { py_exprs(result, _, this, 1) }
@@ -353,6 +388,7 @@ library class ExceptStmt_ extends @py_ExceptStmt, Stmt {
override string toString() { result = "ExceptStmt" }
}
/** INTERNAL: See the class `Exec` for further information. */
library class Exec_ extends @py_Exec, Stmt {
/** Gets the body of this exec statement. */
Expr getBody() { py_exprs(result, _, this, 1) }
@@ -366,6 +402,7 @@ library class Exec_ extends @py_Exec, Stmt {
override string toString() { result = "Exec" }
}
/** INTERNAL: See the class `ExprStmt` for further information. */
library class ExprStmt_ extends @py_Expr_stmt, Stmt {
/** Gets the value of this expr statement. */
Expr getValue() { py_exprs(result, _, this, 1) }
@@ -373,6 +410,7 @@ library class ExprStmt_ extends @py_Expr_stmt, Stmt {
override string toString() { result = "ExprStmt" }
}
/** INTERNAL: See the class `Filter` for further information. */
library class Filter_ extends @py_Filter, Expr {
/** Gets the filtered value of this template filter expression. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -383,10 +421,12 @@ library class Filter_ extends @py_Filter, Expr {
override string toString() { result = "Filter" }
}
/** INTERNAL: See the class `FloorDiv` for further information. */
library class FloorDiv_ extends @py_FloorDiv, Operator {
override string toString() { result = "FloorDiv" }
}
/** INTERNAL: See the class `For` for further information. */
library class For_ extends @py_For, Stmt {
/** Gets the target of this for statement. */
Expr getTarget() { py_exprs(result, _, this, 1) }
@@ -418,6 +458,7 @@ library class For_ extends @py_For, Stmt {
override string toString() { result = "For" }
}
/** INTERNAL: See the class `FormattedValue` for further information. */
library class FormattedValue_ extends @py_FormattedValue, Expr {
/** Gets the expression to be formatted of this formatted value. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -431,6 +472,7 @@ library class FormattedValue_ extends @py_FormattedValue, Expr {
override string toString() { result = "FormattedValue" }
}
/** INTERNAL: See the class `Function` for further information. */
library class Function_ extends @py_Function {
/** Gets the name of this function. */
string getName() { py_strs(result, this, 0) }
@@ -473,9 +515,11 @@ library class Function_ extends @py_Function {
FunctionParent getParent() { py_Functions(this, result) }
/** Gets a textual representation of this element. */
string toString() { result = "Function" }
}
/** INTERNAL: See the class `FunctionExpr` for further information. */
library class FunctionExpr_ extends @py_FunctionExpr, Expr {
/** Gets the name of this function definition. */
string getName() { py_strs(result, this, 2) }
@@ -492,10 +536,13 @@ library class FunctionExpr_ extends @py_FunctionExpr, Expr {
override string toString() { result = "FunctionExpr" }
}
/** INTERNAL: See the class `FunctionParent` for further information. */
library class FunctionParent_ extends @py_Function_parent {
/** Gets a textual representation of this element. */
string toString() { result = "FunctionParent" }
}
/** INTERNAL: See the class `GeneratorExp` for further information. */
library class GeneratorExp_ extends @py_GeneratorExp, Expr {
/** Gets the implementation of this generator expression. */
Function getFunction() { py_Functions(result, this) }
@@ -506,6 +553,7 @@ library class GeneratorExp_ extends @py_GeneratorExp, Expr {
override string toString() { result = "GeneratorExp" }
}
/** INTERNAL: See the class `Global` for further information. */
library class Global_ extends @py_Global, Stmt {
/** Gets the names of this global statement. */
StringList getNames() { py_str_lists(result, this) }
@@ -519,14 +567,17 @@ library class Global_ extends @py_Global, Stmt {
override string toString() { result = "Global" }
}
/** INTERNAL: See the class `Gt` for further information. */
library class Gt_ extends @py_Gt, Cmpop {
override string toString() { result = "Gt" }
}
/** INTERNAL: See the class `GtE` for further information. */
library class GtE_ extends @py_GtE, Cmpop {
override string toString() { result = "GtE" }
}
/** INTERNAL: See the class `If` for further information. */
library class If_ extends @py_If, Stmt {
/** Gets the test of this if statement. */
Expr getTest() { py_exprs(result, _, this, 1) }
@@ -552,6 +603,7 @@ library class If_ extends @py_If, Stmt {
override string toString() { result = "If" }
}
/** INTERNAL: See the class `IfExp` for further information. */
library class IfExp_ extends @py_IfExp, Expr {
/** Gets the test of this if expression. */
Expr getTest() { py_exprs(result, _, this, 2) }
@@ -565,6 +617,7 @@ library class IfExp_ extends @py_IfExp, Expr {
override string toString() { result = "IfExp" }
}
/** INTERNAL: See the class `Import` for further information. */
library class Import_ extends @py_Import, Stmt {
/** Gets the alias list of this import statement. */
AliasList getNames() { py_alias_lists(result, this) }
@@ -578,6 +631,7 @@ library class Import_ extends @py_Import, Stmt {
override string toString() { result = "Import" }
}
/** INTERNAL: See the class `ImportExpr` for further information. */
library class ImportExpr_ extends @py_ImportExpr, Expr {
/** Gets the level of this import expression. */
int getLevel() { py_ints(result, this) }
@@ -591,6 +645,7 @@ library class ImportExpr_ extends @py_ImportExpr, Expr {
override string toString() { result = "ImportExpr" }
}
/** INTERNAL: See the class `ImportStar` for further information. */
library class ImportStar_ extends @py_ImportStar, Stmt {
/** Gets the module of this import * statement. */
Expr getModule() { py_exprs(result, _, this, 1) }
@@ -598,6 +653,7 @@ library class ImportStar_ extends @py_ImportStar, Stmt {
override string toString() { result = "ImportStar" }
}
/** INTERNAL: See the class `ImportMember` for further information. */
library class ImportMember_ extends @py_ImportMember, Expr {
/** Gets the module of this from import. */
Expr getModule() { py_exprs(result, _, this, 2) }
@@ -608,22 +664,27 @@ library class ImportMember_ extends @py_ImportMember, Expr {
override string toString() { result = "ImportMember" }
}
/** INTERNAL: See the class `In` for further information. */
library class In_ extends @py_In, Cmpop {
override string toString() { result = "In" }
}
/** INTERNAL: See the class `Invert` for further information. */
library class Invert_ extends @py_Invert, Unaryop {
override string toString() { result = "Invert" }
}
/** INTERNAL: See the class `Is` for further information. */
library class Is_ extends @py_Is, Cmpop {
override string toString() { result = "Is" }
}
/** INTERNAL: See the class `IsNot` for further information. */
library class IsNot_ extends @py_IsNot, Cmpop {
override string toString() { result = "IsNot" }
}
/** INTERNAL: See the class `Fstring` for further information. */
library class Fstring_ extends @py_Fstring, Expr {
/** Gets the values of this formatted string literal. */
ExprList getValues() { py_expr_lists(result, this, 2) }
@@ -639,6 +700,7 @@ library class Fstring_ extends @py_Fstring, Expr {
override string toString() { result = "Fstring" }
}
/** INTERNAL: See the class `KeyValuePair` for further information. */
library class KeyValuePair_ extends @py_KeyValuePair, DictItem {
/** Gets the location of this key-value pair. */
override Location getLocation() { py_locations(result, this) }
@@ -652,10 +714,12 @@ library class KeyValuePair_ extends @py_KeyValuePair, DictItem {
override string toString() { result = "KeyValuePair" }
}
/** INTERNAL: See the class `LShift` for further information. */
library class LShift_ extends @py_LShift, Operator {
override string toString() { result = "LShift" }
}
/** INTERNAL: See the class `Lambda` for further information. */
library class Lambda_ extends @py_Lambda, Expr {
/** Gets the arguments of this lambda expression. */
Arguments getArgs() { py_arguments(result, this) }
@@ -666,6 +730,7 @@ library class Lambda_ extends @py_Lambda, Expr {
override string toString() { result = "Lambda" }
}
/** INTERNAL: See the class `List` for further information. */
library class List_ extends @py_List, Expr {
/** Gets the element list of this list expression. */
ExprList getElts() { py_expr_lists(result, this, 2) }
@@ -682,6 +747,7 @@ library class List_ extends @py_List, Expr {
override string toString() { result = "List" }
}
/** INTERNAL: See the class `ListComp` for further information. */
library class ListComp_ extends @py_ListComp, Expr {
/** Gets the implementation of this list comprehension. */
Function getFunction() { py_Functions(result, this) }
@@ -704,26 +770,32 @@ library class ListComp_ extends @py_ListComp, Expr {
override string toString() { result = "ListComp" }
}
/** INTERNAL: See the class `Load` for further information. */
library class Load_ extends @py_Load, ExprContext {
override string toString() { result = "Load" }
}
/** INTERNAL: See the class `Lt` for further information. */
library class Lt_ extends @py_Lt, Cmpop {
override string toString() { result = "Lt" }
}
/** INTERNAL: See the class `LtE` for further information. */
library class LtE_ extends @py_LtE, Cmpop {
override string toString() { result = "LtE" }
}
/** INTERNAL: See the class `MatMult` for further information. */
library class MatMult_ extends @py_MatMult, Operator {
override string toString() { result = "MatMult" }
}
/** INTERNAL: See the class `Mod` for further information. */
library class Mod_ extends @py_Mod, Operator {
override string toString() { result = "Mod" }
}
/** INTERNAL: See the class `Module` for further information. */
library class Module_ extends @py_Module {
/** Gets the name of this module. */
string getName() { py_strs(result, this, 0) }
@@ -743,13 +815,16 @@ library class Module_ extends @py_Module {
/** Gets the kind of this module. */
string getKind() { py_strs(result, this, 3) }
/** Gets a textual representation of this element. */
string toString() { result = "Module" }
}
/** INTERNAL: See the class `Mult` for further information. */
library class Mult_ extends @py_Mult, Operator {
override string toString() { result = "Mult" }
}
/** INTERNAL: See the class `Name` for further information. */
library class Name_ extends @py_Name, Expr {
/** Gets the variable of this name expression. */
Variable getVariable() { py_variables(result, this) }
@@ -762,6 +837,7 @@ library class Name_ extends @py_Name, Expr {
override string toString() { result = "Name" }
}
/** INTERNAL: See the class `Nonlocal` for further information. */
library class Nonlocal_ extends @py_Nonlocal, Stmt {
/** Gets the names of this nonlocal statement. */
StringList getNames() { py_str_lists(result, this) }
@@ -775,18 +851,22 @@ library class Nonlocal_ extends @py_Nonlocal, Stmt {
override string toString() { result = "Nonlocal" }
}
/** INTERNAL: See the class `Not` for further information. */
library class Not_ extends @py_Not, Unaryop {
override string toString() { result = "Not" }
}
/** INTERNAL: See the class `NotEq` for further information. */
library class NotEq_ extends @py_NotEq, Cmpop {
override string toString() { result = "NotEq" }
}
/** INTERNAL: See the class `NotIn` for further information. */
library class NotIn_ extends @py_NotIn, Cmpop {
override string toString() { result = "NotIn" }
}
/** INTERNAL: See the class `Num` for further information. */
library class Num_ extends @py_Num, Expr {
/** Gets the value of this numeric literal. */
string getN() { py_numbers(result, this, 2) }
@@ -797,18 +877,22 @@ library class Num_ extends @py_Num, Expr {
override string toString() { result = "Num" }
}
/** INTERNAL: See the class `Or` for further information. */
library class Or_ extends @py_Or, Boolop {
override string toString() { result = "Or" }
}
/** INTERNAL: See the class `Param` for further information. */
library class Param_ extends @py_Param, ExprContext {
override string toString() { result = "Param" }
}
/** INTERNAL: See the class `Pass` for further information. */
library class Pass_ extends @py_Pass, Stmt {
override string toString() { result = "Pass" }
}
/** INTERNAL: See the class `PlaceHolder` for further information. */
library class PlaceHolder_ extends @py_PlaceHolder, Expr {
/** Gets the variable of this template place-holder expression. */
Variable getVariable() { py_variables(result, this) }
@@ -819,10 +903,12 @@ library class PlaceHolder_ extends @py_PlaceHolder, Expr {
override string toString() { result = "PlaceHolder" }
}
/** INTERNAL: See the class `Pow` for further information. */
library class Pow_ extends @py_Pow, Operator {
override string toString() { result = "Pow" }
}
/** INTERNAL: See the class `Print` for further information. */
library class Print_ extends @py_Print, Stmt {
/** Gets the destination of this print statement. */
Expr getDest() { py_exprs(result, _, this, 1) }
@@ -842,10 +928,12 @@ library class Print_ extends @py_Print, Stmt {
override string toString() { result = "Print" }
}
/** INTERNAL: See the class `RShift` for further information. */
library class RShift_ extends @py_RShift, Operator {
override string toString() { result = "RShift" }
}
/** INTERNAL: See the class `Raise` for further information. */
library class Raise_ extends @py_Raise, Stmt {
/** Gets the exception of this raise statement. */
Expr getExc() { py_exprs(result, _, this, 1) }
@@ -865,6 +953,7 @@ library class Raise_ extends @py_Raise, Stmt {
override string toString() { result = "Raise" }
}
/** INTERNAL: See the class `Repr` for further information. */
library class Repr_ extends @py_Repr, Expr {
/** Gets the value of this backtick expression. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -872,6 +961,7 @@ library class Repr_ extends @py_Repr, Expr {
override string toString() { result = "Repr" }
}
/** INTERNAL: See the class `Return` for further information. */
library class Return_ extends @py_Return, Stmt {
/** Gets the value of this return statement. */
Expr getValue() { py_exprs(result, _, this, 1) }
@@ -879,6 +969,7 @@ library class Return_ extends @py_Return, Stmt {
override string toString() { result = "Return" }
}
/** INTERNAL: See the class `Set` for further information. */
library class Set_ extends @py_Set, Expr {
/** Gets the elements of this set expression. */
ExprList getElts() { py_expr_lists(result, this, 2) }
@@ -892,6 +983,7 @@ library class Set_ extends @py_Set, Expr {
override string toString() { result = "Set" }
}
/** INTERNAL: See the class `SetComp` for further information. */
library class SetComp_ extends @py_SetComp, Expr {
/** Gets the implementation of this set comprehension. */
Function getFunction() { py_Functions(result, this) }
@@ -902,6 +994,7 @@ library class SetComp_ extends @py_SetComp, Expr {
override string toString() { result = "SetComp" }
}
/** INTERNAL: See the class `Slice` for further information. */
library class Slice_ extends @py_Slice, Expr {
/** Gets the start of this slice. */
Expr getStart() { py_exprs(result, _, this, 2) }
@@ -915,6 +1008,7 @@ library class Slice_ extends @py_Slice, Expr {
override string toString() { result = "Slice" }
}
/** INTERNAL: See the class `SpecialOperation` for further information. */
library class SpecialOperation_ extends @py_SpecialOperation, Expr {
/** Gets the name of this special operation. */
string getName() { py_strs(result, this, 2) }
@@ -931,6 +1025,7 @@ library class SpecialOperation_ extends @py_SpecialOperation, Expr {
override string toString() { result = "SpecialOperation" }
}
/** INTERNAL: See the class `Starred` for further information. */
library class Starred_ extends @py_Starred, Expr {
/** Gets the value of this starred expression. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -941,10 +1036,12 @@ library class Starred_ extends @py_Starred, Expr {
override string toString() { result = "Starred" }
}
/** INTERNAL: See the class `Store` for further information. */
library class Store_ extends @py_Store, ExprContext {
override string toString() { result = "Store" }
}
/** INTERNAL: See the class `Str` for further information. */
library class Str_ extends @py_Str, Expr {
/** Gets the text of this string literal. */
string getS() { py_strs(result, this, 2) }
@@ -968,6 +1065,7 @@ library class Str_ extends @py_Str, Expr {
override string toString() { result = "Str" }
}
/** INTERNAL: See the class `StringPart` for further information. */
library class StringPart_ extends @py_StringPart {
/** Gets the text of this implicitly concatenated part. */
string getText() { py_strs(result, this, 0) }
@@ -977,9 +1075,11 @@ library class StringPart_ extends @py_StringPart {
StringPartList getParent() { py_StringParts(this, result, _) }
/** Gets a textual representation of this element. */
string toString() { result = "StringPart" }
}
/** INTERNAL: See the class `StringPartList` for further information. */
library class StringPartList_ extends @py_StringPart_list {
BytesOrStr getParent() { py_StringPart_lists(this, result) }
@@ -989,13 +1089,16 @@ library class StringPartList_ extends @py_StringPart_list {
/** Gets the nth item of this implicitly concatenated part list */
StringPart getItem(int index) { py_StringParts(result, this, index) }
/** Gets a textual representation of this element. */
string toString() { result = "StringPartList" }
}
/** INTERNAL: See the class `Sub` for further information. */
library class Sub_ extends @py_Sub, Operator {
override string toString() { result = "Sub" }
}
/** INTERNAL: See the class `Subscript` for further information. */
library class Subscript_ extends @py_Subscript, Expr {
/** Gets the value of this subscript expression. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -1009,6 +1112,7 @@ library class Subscript_ extends @py_Subscript, Expr {
override string toString() { result = "Subscript" }
}
/** INTERNAL: See the class `TemplateDottedNotation` for further information. */
library class TemplateDottedNotation_ extends @py_TemplateDottedNotation, Expr {
/** Gets the object of this template dotted notation expression. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -1022,6 +1126,7 @@ library class TemplateDottedNotation_ extends @py_TemplateDottedNotation, Expr {
override string toString() { result = "TemplateDottedNotation" }
}
/** INTERNAL: See the class `TemplateWrite` for further information. */
library class TemplateWrite_ extends @py_TemplateWrite, Stmt {
/** Gets the value of this template write statement. */
Expr getValue() { py_exprs(result, _, this, 1) }
@@ -1029,6 +1134,7 @@ library class TemplateWrite_ extends @py_TemplateWrite, Stmt {
override string toString() { result = "TemplateWrite" }
}
/** INTERNAL: See the class `Try` for further information. */
library class Try_ extends @py_Try, Stmt {
/** Gets the body of this try statement. */
StmtList getBody() { py_stmt_lists(result, this, 1) }
@@ -1069,6 +1175,7 @@ library class Try_ extends @py_Try, Stmt {
override string toString() { result = "Try" }
}
/** INTERNAL: See the class `Tuple` for further information. */
library class Tuple_ extends @py_Tuple, Expr {
/** Gets the elements of this tuple expression. */
ExprList getElts() { py_expr_lists(result, this, 2) }
@@ -1087,14 +1194,17 @@ library class Tuple_ extends @py_Tuple, Expr {
override string toString() { result = "Tuple" }
}
/** INTERNAL: See the class `UAdd` for further information. */
library class UAdd_ extends @py_UAdd, Unaryop {
override string toString() { result = "UAdd" }
}
/** INTERNAL: See the class `USub` for further information. */
library class USub_ extends @py_USub, Unaryop {
override string toString() { result = "USub" }
}
/** INTERNAL: See the class `UnaryExpr` for further information. */
library class UnaryExpr_ extends @py_UnaryExpr, Expr {
/** Gets the operator of this unary expression. */
Unaryop getOp() { py_unaryops(result, _, this) }
@@ -1105,6 +1215,7 @@ library class UnaryExpr_ extends @py_UnaryExpr, Expr {
override string toString() { result = "UnaryExpr" }
}
/** INTERNAL: See the class `While` for further information. */
library class While_ extends @py_While, Stmt {
/** Gets the test of this while statement. */
Expr getTest() { py_exprs(result, _, this, 1) }
@@ -1130,6 +1241,7 @@ library class While_ extends @py_While, Stmt {
override string toString() { result = "While" }
}
/** INTERNAL: See the class `With` for further information. */
library class With_ extends @py_With, Stmt {
/** Gets the context manager of this with statement. */
Expr getContextExpr() { py_exprs(result, _, this, 1) }
@@ -1152,6 +1264,7 @@ library class With_ extends @py_With, Stmt {
override string toString() { result = "With" }
}
/** INTERNAL: See the class `Yield` for further information. */
library class Yield_ extends @py_Yield, Expr {
/** Gets the value of this yield expression. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -1159,6 +1272,7 @@ library class Yield_ extends @py_Yield, Expr {
override string toString() { result = "Yield" }
}
/** INTERNAL: See the class `YieldFrom` for further information. */
library class YieldFrom_ extends @py_YieldFrom, Expr {
/** Gets the value of this yield-from expression. */
Expr getValue() { py_exprs(result, _, this, 2) }
@@ -1166,6 +1280,7 @@ library class YieldFrom_ extends @py_YieldFrom, Expr {
override string toString() { result = "YieldFrom" }
}
/** INTERNAL: See the class `Alias` for further information. */
library class Alias_ extends @py_alias {
/** Gets the value of this alias. */
Expr getValue() { py_exprs(result, _, this, 0) }
@@ -1175,9 +1290,11 @@ library class Alias_ extends @py_alias {
AliasList getParent() { py_aliases(this, result, _) }
/** Gets a textual representation of this element. */
string toString() { result = "Alias" }
}
/** INTERNAL: See the class `AliasList` for further information. */
library class AliasList_ extends @py_alias_list {
Import getParent() { py_alias_lists(this, result) }
@@ -1187,9 +1304,11 @@ library class AliasList_ extends @py_alias_list {
/** Gets the nth item of this alias list */
Alias getItem(int index) { py_aliases(result, this, index) }
/** Gets a textual representation of this element. */
string toString() { result = "AliasList" }
}
/** INTERNAL: See the class `Arguments` for further information. */
library class Arguments_ extends @py_arguments {
/** Gets the keyword default values of this parameters definition. */
ExprList getKwDefaults() { py_expr_lists(result, this, 0) }
@@ -1235,33 +1354,45 @@ library class Arguments_ extends @py_arguments {
ArgumentsParent getParent() { py_arguments(this, result) }
/** Gets a textual representation of this element. */
string toString() { result = "Arguments" }
}
/** INTERNAL: See the class `ArgumentsParent` for further information. */
library class ArgumentsParent_ extends @py_arguments_parent {
/** Gets a textual representation of this element. */
string toString() { result = "ArgumentsParent" }
}
/** INTERNAL: See the class `AstNode` for further information. */
library class AstNode_ extends @py_ast_node {
/** Gets a textual representation of this element. */
string toString() { result = "AstNode" }
}
/** INTERNAL: See the class `BoolParent` for further information. */
library class BoolParent_ extends @py_bool_parent {
/** Gets a textual representation of this element. */
string toString() { result = "BoolParent" }
}
/** INTERNAL: See the class `Boolop` for further information. */
library class Boolop_ extends @py_boolop {
BoolExpr getParent() { py_boolops(this, _, result) }
/** Gets a textual representation of this element. */
string toString() { result = "Boolop" }
}
/** INTERNAL: See the class `Cmpop` for further information. */
library class Cmpop_ extends @py_cmpop {
CmpopList getParent() { py_cmpops(this, _, result, _) }
/** Gets a textual representation of this element. */
string toString() { result = "Cmpop" }
}
/** INTERNAL: See the class `CmpopList` for further information. */
library class CmpopList_ extends @py_cmpop_list {
Compare getParent() { py_cmpop_lists(this, result) }
@@ -1271,9 +1402,11 @@ library class CmpopList_ extends @py_cmpop_list {
/** Gets the nth item of this comparison operator list */
Cmpop getItem(int index) { py_cmpops(result, _, this, index) }
/** Gets a textual representation of this element. */
string toString() { result = "CmpopList" }
}
/** INTERNAL: See the class `Comprehension` for further information. */
library class Comprehension_ extends @py_comprehension {
/** Gets the location of this comprehension. */
Location getLocation() { py_locations(result, this) }
@@ -1295,9 +1428,11 @@ library class Comprehension_ extends @py_comprehension {
ComprehensionList getParent() { py_comprehensions(this, result, _) }
/** Gets a textual representation of this element. */
string toString() { result = "Comprehension" }
}
/** INTERNAL: See the class `ComprehensionList` for further information. */
library class ComprehensionList_ extends @py_comprehension_list {
ListComp getParent() { py_comprehension_lists(this, result) }
@@ -1307,15 +1442,19 @@ library class ComprehensionList_ extends @py_comprehension_list {
/** Gets the nth item of this comprehension list */
Comprehension getItem(int index) { py_comprehensions(result, this, index) }
/** Gets a textual representation of this element. */
string toString() { result = "ComprehensionList" }
}
/** INTERNAL: See the class `DictItem` for further information. */
library class DictItem_ extends @py_dict_item {
DictItemList getParent() { py_dict_items(this, _, result, _) }
/** Gets a textual representation of this element. */
string toString() { result = "DictItem" }
}
/** INTERNAL: See the class `DictItemList` for further information. */
library class DictItemList_ extends @py_dict_item_list {
DictItemListParent getParent() { py_dict_item_lists(this, result) }
@@ -1325,13 +1464,17 @@ library class DictItemList_ extends @py_dict_item_list {
/** Gets the nth item of this dict_item list */
DictItem getItem(int index) { py_dict_items(result, _, this, index) }
/** Gets a textual representation of this element. */
string toString() { result = "DictItemList" }
}
/** INTERNAL: See the class `DictItemListParent` for further information. */
library class DictItemListParent_ extends @py_dict_item_list_parent {
/** Gets a textual representation of this element. */
string toString() { result = "DictItemListParent" }
}
/** INTERNAL: See the class `Expr` for further information. */
library class Expr_ extends @py_expr {
/** Gets the location of this expression. */
Location getLocation() { py_locations(result, this) }
@@ -1341,19 +1484,25 @@ library class Expr_ extends @py_expr {
ExprParent getParent() { py_exprs(this, _, result, _) }
/** Gets a textual representation of this element. */
string toString() { result = "Expr" }
}
/** INTERNAL: See the class `ExprContext` for further information. */
library class ExprContext_ extends @py_expr_context {
ExprContextParent getParent() { py_expr_contexts(this, _, result) }
/** Gets a textual representation of this element. */
string toString() { result = "ExprContext" }
}
/** INTERNAL: See the class `ExprContextParent` for further information. */
library class ExprContextParent_ extends @py_expr_context_parent {
/** Gets a textual representation of this element. */
string toString() { result = "ExprContextParent" }
}
/** INTERNAL: See the class `ExprList` for further information. */
library class ExprList_ extends @py_expr_list {
ExprListParent getParent() { py_expr_lists(this, result, _) }
@@ -1363,21 +1512,29 @@ library class ExprList_ extends @py_expr_list {
/** Gets the nth item of this expression list */
Expr getItem(int index) { py_exprs(result, _, this, index) }
/** Gets a textual representation of this element. */
string toString() { result = "ExprList" }
}
/** INTERNAL: See the class `ExprListParent` for further information. */
library class ExprListParent_ extends @py_expr_list_parent {
/** Gets a textual representation of this element. */
string toString() { result = "ExprListParent" }
}
/** INTERNAL: See the class `ExprOrStmt` for further information. */
library class ExprOrStmt_ extends @py_expr_or_stmt {
/** Gets a textual representation of this element. */
string toString() { result = "ExprOrStmt" }
}
/** INTERNAL: See the class `ExprParent` for further information. */
library class ExprParent_ extends @py_expr_parent {
/** Gets a textual representation of this element. */
string toString() { result = "ExprParent" }
}
/** INTERNAL: See the class `Keyword` for further information. */
library class Keyword_ extends @py_keyword, DictItem {
/** Gets the location of this keyword argument. */
override Location getLocation() { py_locations(result, this) }
@@ -1391,33 +1548,44 @@ library class Keyword_ extends @py_keyword, DictItem {
override string toString() { result = "Keyword" }
}
/** INTERNAL: See the class `LocationParent` for further information. */
library class LocationParent_ extends @py_location_parent {
/** Gets a textual representation of this element. */
string toString() { result = "LocationParent" }
}
/** INTERNAL: See the class `Operator` for further information. */
library class Operator_ extends @py_operator {
BinaryExpr getParent() { py_operators(this, _, result) }
/** Gets a textual representation of this element. */
string toString() { result = "Operator" }
}
/** INTERNAL: See the class `Parameter` for further information. */
library class Parameter_ extends @py_parameter {
/** Gets a textual representation of this element. */
string toString() { result = "Parameter" }
}
/** INTERNAL: See the class `Scope` for further information. */
library class Scope_ extends @py_scope {
/** Gets a textual representation of this element. */
string toString() { result = "Scope" }
}
/** INTERNAL: See the class `Stmt` for further information. */
library class Stmt_ extends @py_stmt {
/** Gets the location of this statement. */
Location getLocation() { py_locations(result, this) }
StmtList getParent() { py_stmts(this, _, result, _) }
/** Gets a textual representation of this element. */
string toString() { result = "Stmt" }
}
/** INTERNAL: See the class `StmtList` for further information. */
library class StmtList_ extends @py_stmt_list {
StmtListParent getParent() { py_stmt_lists(this, result, _) }
@@ -1427,13 +1595,17 @@ library class StmtList_ extends @py_stmt_list {
/** Gets the nth item of this statement list */
Stmt getItem(int index) { py_stmts(result, _, this, index) }
/** Gets a textual representation of this element. */
string toString() { result = "StmtList" }
}
/** INTERNAL: See the class `StmtListParent` for further information. */
library class StmtListParent_ extends @py_stmt_list_parent {
/** Gets a textual representation of this element. */
string toString() { result = "StmtListParent" }
}
/** INTERNAL: See the class `StringList` for further information. */
library class StringList_ extends @py_str_list {
StrListParent getParent() { py_str_lists(this, result) }
@@ -1443,23 +1615,32 @@ library class StringList_ extends @py_str_list {
/** Gets the nth item of this string list */
string getItem(int index) { py_strs(result, this, index) }
/** Gets a textual representation of this element. */
string toString() { result = "StringList" }
}
/** INTERNAL: See the class `StrListParent` for further information. */
library class StrListParent_ extends @py_str_list_parent {
/** Gets a textual representation of this element. */
string toString() { result = "StrListParent" }
}
/** INTERNAL: See the class `StrParent` for further information. */
library class StrParent_ extends @py_str_parent {
/** Gets a textual representation of this element. */
string toString() { result = "StrParent" }
}
/** INTERNAL: See the class `Unaryop` for further information. */
library class Unaryop_ extends @py_unaryop {
UnaryExpr getParent() { py_unaryops(this, _, result) }
/** Gets a textual representation of this element. */
string toString() { result = "Unaryop" }
}
/** INTERNAL: See the class `VariableParent` for further information. */
library class VariableParent_ extends @py_variable_parent {
/** Gets a textual representation of this element. */
string toString() { result = "VariableParent" }
}

View File

@@ -1,3 +1,7 @@
/**
* Provides classes representing Python classes.
*/
import python
/**
@@ -37,6 +41,7 @@ class ClassExpr extends ClassExpr_ {
result = this.getStarargs()
}
/** Gets a call corresponding to a decorator of this class definition. */
Call getADecoratorCall() {
result.getArg(0) = this or
result.getArg(0) = this.getADecoratorCall()
@@ -114,9 +119,10 @@ class Class extends Class_, Scope, AstNode {
/** Gets the name used to define this class */
override string getName() { result = Class_.super.getName() }
/** Holds if this expression may have a side effect (as determined purely from its syntax). */
predicate hasSideEffects() { any() }
/** Whether this is probably a mixin (has 'mixin' or similar in name or docstring) */
/** Holds if this is probably a mixin (has 'mixin' or similar in name or docstring) */
predicate isProbableMixin() {
(
this.getName().toLowerCase().matches("%mixin%")
@@ -129,6 +135,7 @@ class Class extends Class_, Scope, AstNode {
override AstNode getAChildNode() { result = this.getAStmt() }
/** Gets a decorator of this class. */
Expr getADecorator() { result = this.getParent().getADecorator() }
/** Gets the metaclass expression */

View File

@@ -1,3 +1,7 @@
/**
* Provides classes representing comments in Python.
*/
import python
/** A source code comment */
@@ -10,6 +14,7 @@ class Comment extends @py_comment {
Location getLocation() { py_comments(this, _, result) }
/** Gets a textual representation of this element. */
string toString() { result = "Comment " + this.getText() }
/**
@@ -51,22 +56,33 @@ class CommentBlock extends @py_comment {
private Comment last() { comment_block_part(this, result, this.length()) }
/** Gets a textual representation of this element. */
string toString() { result = "Comment block" }
/** The length of this comment block (in comments) */
int length() { result = max(int i | comment_block_part(this, _, i)) }
predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) {
this.(Comment).getLocation().hasLocationInfo(filepath, bl, bc, _, _) and
exists(Comment end | end = this.last() | end.getLocation().hasLocationInfo(_, _, _, el, ec))
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) { this.(Comment).getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
exists(Comment end | end = this.last() | end.getLocation().hasLocationInfo(_, _, _, endline, endcolumn))
}
/** Holds if this comment block contains `c`. */
predicate contains(Comment c) {
comment_block_part(this, c, _)
or
this = c
}
/** Gets a string representation of this comment block. */
string getContents() {
result =
concat(Comment c, int i |

View File

@@ -1,3 +1,7 @@
/**
* Provides classes representing comparison operators.
*/
import python
/** A class representing the six comparison operators, ==, !=, <, <=, > and >=. */
@@ -34,6 +38,7 @@ class CompareOp extends int {
this = ge() and result = le()
}
/** Gets the textual representation of `this`. */
string repr() {
this = eq() and result = "=="
or
@@ -48,6 +53,7 @@ class CompareOp extends int {
this = ge() and result = ">="
}
/** Holds if `op` is the `Cmpop` corresponding to `this`. */
predicate forOp(Cmpop op) {
op instanceof Eq and this = eq()
or
@@ -70,16 +76,22 @@ class CompareOp extends int {
}
}
/** The `CompareOp` for "equals". */
CompareOp eq() { result = 1 }
/** The `CompareOp` for "not equals". */
CompareOp ne() { result = 2 }
/** The `CompareOp` for "less than". */
CompareOp lt() { result = 3 }
/** The `CompareOp` for "less than or equal to". */
CompareOp le() { result = 4 }
/** The `CompareOp` for "greater than". */
CompareOp gt() { result = 5 }
/** The `CompareOp` for "greater than or equal to". */
CompareOp ge() { result = 6 }
/* Workaround precision limits in floating point numbers */

View File

@@ -7,6 +7,7 @@ class Expr extends Expr_, AstNode {
/** Gets the scope of this expression */
override Scope getScope() { py_scopes(this, result) }
/** Gets a textual representation of this element. */
override string toString() { result = "Expression" }
/** Gets the module in which this expression occurs */

View File

@@ -10,8 +10,21 @@ class File extends Container {
/** DEPRECATED: Use `getAbsolutePath` instead. */
deprecated string getFullName() { result = this.getAbsolutePath() }
predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) {
this.getAbsolutePath() = filepath and bl = 0 and bc = 0 and el = 0 and ec = 0
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getAbsolutePath() = filepath and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
}
/** Whether this file is a source code file. */
@@ -79,8 +92,21 @@ class Folder extends Container {
/** DEPRECATED: Use `getBaseName` instead. */
deprecated string getSimple() { folders(this, _, result) }
predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) {
this.getAbsolutePath() = filepath and bl = 0 and bc = 0 and el = 0 and ec = 0
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getAbsolutePath() = filepath and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
}
override string getAbsolutePath() { folders(this, result, _) }
@@ -367,30 +393,48 @@ class Location extends @location {
locations_ast(this, _, _, _, _, result)
}
/** Gets a textual representation of this element. */
string toString() {
result = this.getPath().getAbsolutePath() + ":" + this.getStartLine().toString()
}
predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) {
exists(File f | f.getAbsolutePath() = filepath |
locations_default(this, f, bl, bc, el, ec)
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) { exists(File f | f.getAbsolutePath() = filepath |
locations_default(this, f, startline, startcolumn, endline, endcolumn)
or
exists(Module m | m.getFile() = f | locations_ast(this, m, bl, bc, el, ec))
exists(Module m | m.getFile() = f | locations_ast(this, m, startline, startcolumn, endline, endcolumn))
)
}
}
/** A non-empty line in the source code */
class Line extends @py_line {
predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) {
exists(Module m |
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) { exists(Module m |
m.getFile().getAbsolutePath() = filepath and
el = bl and
bc = 1 and
py_line_lengths(this, m, bl, ec)
endline = startline and
startcolumn = 1 and
py_line_lengths(this, m, startline, endcolumn)
)
}
/** Gets a textual representation of this element. */
string toString() {
exists(Module m | py_line_lengths(this, m, _, _) |
result = m.getFile().getShortName() + ":" + this.getLineNumber().toString()

View File

@@ -139,6 +139,7 @@ class ControlFlowNode extends @py_flow_node {
/** Gets the syntactic element corresponding to this flow node */
AstNode getNode() { py_flow_bb_node(this, result, _, _) }
/** Gets a textual representation of this element. */
string toString() {
exists(Scope s | s.getEntryNode() = this | result = "Entry node for " + s.toString())
or
@@ -1014,6 +1015,7 @@ class BasicBlock extends @py_flow_node {
/** Gets the nth node in this basic block */
ControlFlowNode getNode(int n) { py_flow_bb_node(result, _, this, n) }
/** Gets a textual representation of this element. */
string toString() { result = "BasicBlock" }
/** Whether this basic block strictly dominates the other */
@@ -1079,9 +1081,17 @@ class BasicBlock extends @py_flow_node {
this.getASuccessor().reachesExit()
}
predicate hasLocationInfo(string file, int line, int col, int endl, int endc) {
this.startLocationInfo(file, line, col) and
this.endLocationInfo(endl, endc)
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) { this.startLocationInfo(filepath, startline, startcolumn) and
this.endLocationInfo(endline, endcolumn)
}
/** Gets a true successor to this basic block */

View File

@@ -76,6 +76,7 @@ class SsaVariable extends @py_ssa_var {
result = this.getAPhiInput().getAnUltimateDefinition()
}
/** Gets a textual representation of this element. */
string toString() { result = "SSA Variable " + this.getId() }
Location getLocation() { result = this.getDefinition().getLocation() }

View File

@@ -90,8 +90,16 @@ class AugAssign extends AugAssign_ {
/* syntax: Expr += Expr */
override Expr getASubExpression() { result = this.getOperation() }
/**
* Gets the target of this augmented assignment statement.
* That is, the `a` in `a += b`.
*/
Expr getTarget() { result = this.getOperation().(BinaryExpr).getLeft() }
/**
* Gets the value of this augmented assignment statement.
* That is, the `b` in `a += b`.
*/
Expr getValue() { result = this.getOperation().(BinaryExpr).getRight() }
override Stmt getASubStatement() { none() }
@@ -405,11 +413,13 @@ class TemplateWrite extends TemplateWrite_ {
override Stmt getASubStatement() { none() }
}
/** An asynchronous `for` statement, such as `async for varname in Expr: ...` */
class AsyncFor extends For {
/* syntax: async for varname in Expr: ... */
AsyncFor() { this.isAsync() }
}
/** An asynchronous `with` statement, such as `async with varname as Expr: ...` */
class AsyncWith extends With {
/* syntax: async with Expr as varname: ... */
AsyncWith() { this.isAsync() }
@@ -417,10 +427,11 @@ class AsyncWith extends With {
/** A list of statements */
class StmtList extends StmtList_ {
/** Whether this list of statements contains s */
/** Holds if this list of statements contains the AST node `a` */
predicate contains(AstNode a) {
exists(Stmt item | item = this.getAnItem() | item = a or item.contains(a))
}
/** Gets the last item in this list of statements, if any. */
Stmt getLastItem() { result = this.getItem(max(int i | exists(this.getItem(i)))) }
}

View File

@@ -13,6 +13,7 @@ class Variable extends @py_variable {
/** Gets the identifier (name) of this variable */
string getId() { variable(this, _, result) }
/** Gets a textual representation of this element. */
string toString() { result = "Variable " + this.getId() }
/** Gets an access (load or store) of this variable */

View File

@@ -24,6 +24,7 @@ newtype TTaintTrackingContext =
* Used to track taint through calls accurately and reasonably efficiently.
*/
class TaintTrackingContext extends TTaintTrackingContext {
/** Gets a textual representation of this element. */
string toString() {
this = TNoParam() and result = ""
or
@@ -66,6 +67,7 @@ private newtype TAttributePath =
* Used for tracking tainted attributes of objects.
*/
abstract class AttributePath extends TAttributePath {
/** Gets a textual representation of this element. */
abstract string toString();
abstract string extension();
@@ -126,6 +128,7 @@ newtype TTaintTrackingNode =
* Used for context-sensitive path-aware taint-tracking.
*/
class TaintTrackingNode extends TTaintTrackingNode {
/** Gets a textual representation of this element. */
string toString() {
if this.getPath() instanceof NoAttribute
then result = this.getTaintKind().repr()

View File

@@ -355,6 +355,7 @@ abstract class Sanitizer extends string {
* class to provide their own sources.
*/
abstract class TaintSource extends @py_flow_node {
/** Gets a textual representation of this element. */
string toString() { result = "Taint source" }
/**
@@ -378,8 +379,16 @@ abstract class TaintSource extends @py_flow_node {
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) {
this.getLocation().hasLocationInfo(fp, bl, bc, el, ec)
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) { this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets a TaintedNode for this taint source */
@@ -470,6 +479,7 @@ private class SequenceExtends extends DataFlowExtension::DataFlowNode {
* class to provide their own sink nodes.
*/
abstract class TaintSink extends @py_flow_node {
/** Gets a textual representation of this element. */
string toString() { result = "Taint sink" }
/**
@@ -482,8 +492,16 @@ abstract class TaintSink extends @py_flow_node {
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) {
this.getLocation().hasLocationInfo(fp, bl, bc, el, ec)
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) { this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -495,6 +513,7 @@ abstract class TaintSink extends @py_flow_node {
module DataFlowExtension {
/** A control flow node that modifies the basic data-flow. */
abstract class DataFlowNode extends @py_flow_node {
/** Gets a textual representation of this element. */
string toString() { result = "Dataflow extension node" }
/**
@@ -641,6 +660,7 @@ module DataFlow {
abstract EssaVariable asVariable();
/** Gets a textual representation of this element. */
abstract string toString();
abstract Scope getScope();
@@ -660,6 +680,7 @@ module DataFlow {
override EssaVariable asVariable() { none() }
/** Gets a textual representation of this element. */
override string toString() { result = this.asAstNode().toString() }
override Scope getScope() { result = this.asCfgNode().getScope() }
@@ -674,6 +695,7 @@ module DataFlow {
override EssaVariable asVariable() { this = TEssaNode(result) }
/** Gets a textual representation of this element. */
override string toString() { result = this.asVariable().toString() }
override Scope getScope() { result = this.asVariable().getScope() }

View File

@@ -29,6 +29,7 @@ abstract class SsaSourceVariable extends @py_variable {
abstract ControlFlowNode getScopeEntryDefinition();
/** Gets a textual representation of this element. */
string toString() { result = "SsaSourceVariable " + this.getName() }
/** Gets a use of this variable, either explicit or implicit. */

View File

@@ -24,6 +24,7 @@ class EssaVariable extends TEssaDefinition {
/** Gets the name of this variable. */
string getName() { result = this.getSourceVariable().getName() }
/** Gets a textual representation of this element. */
string toString() { result = "SSA variable " + this.getName() }
/**
@@ -131,6 +132,7 @@ private newtype TEssaDefinition =
* and exactly one variable for each definition.
*/
abstract class EssaDefinition extends TEssaDefinition {
/** Gets a textual representation of this element. */
string toString() { result = "EssaDefinition" }
/** Gets the source variable for which this a definition, either explicit or implicit. */

View File

@@ -36,6 +36,7 @@ class Value extends TObject {
this != ObjectInternal::undefined()
}
/** Gets a textual representation of this element. */
string toString() { result = this.(ObjectInternal).toString() }
/** Gets a `ControlFlowNode` that refers to this object. */
@@ -73,15 +74,28 @@ class Value extends TObject {
*/
predicate isBuiltin() { this.(ObjectInternal).isBuiltin() }
predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) {
this.(ObjectInternal).getOrigin().getLocation().hasLocationInfo(filepath, bl, bc, el, ec)
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this
.(ObjectInternal)
.getOrigin()
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
or
not exists(this.(ObjectInternal).getOrigin()) and
filepath = "" and
bl = 0 and
bc = 0 and
el = 0 and
ec = 0
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
}
/**
@@ -882,6 +896,7 @@ class PropertyValue extends Value {
/** A method-resolution-order sequence of classes */
class MRO extends TClassList {
/** Gets a textual representation of this element. */
string toString() { result = this.(ClassList).toString() }
/** Gets the `n`th class in this MRO */

View File

@@ -17,6 +17,7 @@ import semmle.python.objects.Sequences
import semmle.python.objects.Descriptors
class ObjectInternal extends TObject {
/** Gets a textual representation of this element. */
abstract string toString();
/**

View File

@@ -1,3 +1,5 @@
/** Contains the internal algebraic datatype backing the various values tracked by the points-to implementation. */
import python
private import semmle.python.types.Builtins
private import semmle.python.objects.ObjectInternal
@@ -10,19 +12,19 @@ private import semmle.python.pointsto.PointsToContext
*/
cached
newtype TObject =
/* Builtin class objects */
/** Builtin class objects */
TBuiltinClassObject(Builtin bltn) {
bltn.isClass() and
not bltn = Builtin::unknownType() and
not bltn = Builtin::special("type")
} or
/* Builtin function objects (module members) */
/** Builtin function objects (module members) */
TBuiltinFunctionObject(Builtin bltn) { bltn.isFunction() } or
/* Builtin method objects (class members) */
/** Builtin method objects (class members) */
TBuiltinMethodObject(Builtin bltn) { bltn.isMethod() } or
/* Builtin module objects */
/** Builtin module objects */
TBuiltinModuleObject(Builtin bltn) { bltn.isModule() } or
/* Other builtin objects from the interpreter */
/** Other builtin objects from the interpreter */
TBuiltinOpaqueObject(Builtin bltn) {
not bltn.isClass() and
not bltn.isFunction() and
@@ -34,31 +36,31 @@ newtype TObject =
not exists(bltn.strValue()) and
not py_special_objects(bltn, _)
} or
/* Python function objects (including lambdas) */
/** Python function objects (including lambdas) */
TPythonFunctionObject(ControlFlowNode callable) { callable.getNode() instanceof CallableExpr } or
/* Python class objects */
/** Python class objects */
TPythonClassObject(ControlFlowNode classexpr) { classexpr.getNode() instanceof ClassExpr } or
/* Package objects */
/** Package objects */
TPackageObject(Folder f) { isPreferredModuleForName(f, _) } or
/* Python module objects */
/** Python module objects */
TPythonModule(Module m) {
not m.isPackage() and
isPreferredModuleForName(m.getFile(), _) and
not exists(SyntaxError se | se.getFile() = m.getFile())
} or
/* `True` */
/** `True` */
TTrue() or
/* `False` */
/** `False` */
TFalse() or
/* `None` */
/** `None` */
TNone() or
/* Represents any value about which nothing useful is known */
/** Represents any value about which nothing useful is known */
TUnknown() or
/* Represents any value known to be a class, but not known to be any specific class */
/** Represents any value known to be a class, but not known to be any specific class */
TUnknownClass() or
/* Represents the absence of a value. Used by points-to for tracking undefined variables */
/** Represents the absence of a value. Used by points-to for tracking undefined variables */
TUndefined() or
/* The integer `n` */
/** The integer `n` */
TInt(int n) {
// Powers of 2 are used for flags
is_power_2(n)
@@ -76,9 +78,9 @@ newtype TObject =
or
n = any(Builtin b).intValue()
} or
/* The float `f` */
/** The float `f` */
TFloat(float f) { f = any(FloatLiteral num).getValue() } or
/* The unicode string `s` */
/** The unicode string `s` */
TUnicode(string s) {
// Any string explicitly mentioned in the source code.
exists(StrConst str |
@@ -94,7 +96,7 @@ newtype TObject =
or
s = "__main__"
} or
/* The byte string `s` */
/** The byte string `s` */
TBytes(string s) {
// Any string explicitly mentioned in the source code.
exists(StrConst str |
@@ -110,74 +112,74 @@ newtype TObject =
or
s = "__main__"
} or
/* An instance of `cls`, instantiated at `instantiation` given the `context`. */
/** An instance of `cls`, instantiated at `instantiation` given the `context`. */
TSpecificInstance(ControlFlowNode instantiation, ClassObjectInternal cls, PointsToContext context) {
PointsToInternal::pointsTo(instantiation.(CallNode).getFunction(), context, cls, _) and
cls.isSpecial() = false
or
literal_instantiation(instantiation, cls, context)
} or
/* A non-specific instance `cls` which enters the scope at `def` given the callee `context`. */
/** A non-specific instance `cls` which enters the scope at `def` given the callee `context`. */
TSelfInstance(ParameterDefinition def, PointsToContext context, PythonClassObjectInternal cls) {
self_parameter(def, context, cls)
} or
/* A bound method */
/** A bound method */
TBoundMethod(ObjectInternal self, CallableObjectInternal function) {
any(ObjectInternal obj).binds(self, _, function) and
function.isDescriptor() = true
} or
/* Represents any value whose class is known, but nothing else */
/** Represents any value whose class is known, but nothing else */
TUnknownInstance(BuiltinClassObjectInternal cls) {
cls != ObjectInternal::superType() and
cls != ObjectInternal::builtin("bool") and
cls != ObjectInternal::noneType()
} or
/* Represents an instance of `super` */
/** Represents an instance of `super` */
TSuperInstance(ObjectInternal self, ClassObjectInternal startclass) {
super_instantiation(_, self, startclass, _)
} or
/* Represents an instance of `classmethod` */
/** Represents an instance of `classmethod` */
TClassMethod(CallNode instantiation, CallableObjectInternal function) {
class_method(instantiation, function, _)
} or
/* Represents an instance of `staticmethod` */
/** Represents an instance of `staticmethod` */
TStaticMethod(CallNode instantiation, CallableObjectInternal function) {
static_method(instantiation, function, _)
} or
/* Represents a builtin tuple */
/** Represents a builtin tuple */
TBuiltinTuple(Builtin bltn) { bltn.getClass() = Builtin::special("tuple") } or
/* Represents a tuple in the Python source */
/** Represents a tuple in the Python source */
TPythonTuple(TupleNode origin, PointsToContext context) {
origin.isLoad() and
context.appliesTo(origin)
} or
/* Varargs tuple */
/** Varargs tuple */
TVarargsTuple(CallNode call, PointsToContext context, int offset, int length) {
InterProceduralPointsTo::varargs_tuple(call, context, _, _, offset, length)
} or
/* `type` */
/** `type` */
TType() or
/* Represents an instance of `property` */
/** Represents an instance of `property` */
TProperty(CallNode call, Context ctx, CallableObjectInternal getter) {
PointsToInternal::pointsTo(call.getFunction(), ctx, ObjectInternal::property(), _) and
PointsToInternal::pointsTo(call.getArg(0), ctx, getter, _)
} or
/* Represents the `setter` or `deleter` method of a property object. */
/** Represents the `setter` or `deleter` method of a property object. */
TPropertySetterOrDeleter(PropertyInternal property, string method) {
exists(AttrNode attr | PointsToInternal::pointsTo(attr.getObject(method), _, property, _)) and
(method = "setter" or method = "deleter")
} or
/* Represents a dynamically created class */
/** Represents a dynamically created class */
TDynamicClass(CallNode instantiation, ClassObjectInternal metacls, PointsToContext context) {
PointsToInternal::pointsTo(instantiation.getFunction(), context, metacls, _) and
not count(instantiation.getAnArg()) = 1 and
Types::getMro(metacls).contains(TType())
} or
/* Represents `sys.version_info`. Acts like a tuple with a range of values depending on the version being analysed. */
/** Represents `sys.version_info`. Acts like a tuple with a range of values depending on the version being analysed. */
TSysVersionInfo() or
/* Represents a module that is inferred to perhaps exist, but is not present in the database. */
/** Represents a module that is inferred to perhaps exist, but is not present in the database. */
TAbsentModule(string name) { missing_imported_module(_, _, name) } or
/* Represents an attribute of a module that is inferred to perhaps exist, but is not present in the database. */
/** Represents an attribute of a module that is inferred to perhaps exist, but is not present in the database. */
TAbsentModuleAttribute(AbsentModuleObjectInternal mod, string attrname) {
(
PointsToInternal::pointsTo(any(AttrNode attr).getObject(attrname), _, mod, _)
@@ -189,9 +191,9 @@ newtype TObject =
not common_module_name(modname + "." + attrname)
)
} or
/* Opaque object representing the result of calling a decorator on a function that we don't understand */
/** Opaque object representing the result of calling a decorator on a function that we don't understand */
TDecoratedFunction(CallNode call) { call.isFunctionDecoratorCall() } or
/* Represents a subscript operation applied to a type. For type-hint analysis */
/** Represents a subscript operation applied to a type. For type-hint analysis */
TSubscriptedType(ObjectInternal generic, ObjectInternal index) {
isType(generic) and
generic.isNotSubscriptedType() and
@@ -199,6 +201,7 @@ newtype TObject =
Expressions::subscriptPartsPointsTo(_, _, generic, index)
}
/** Holds if the object `t` is a type. */
predicate isType(ObjectInternal t) {
t.isClass() = true
or
@@ -421,7 +424,7 @@ predicate missing_imported_module(ControlFlowNode imp, Context ctx, string name)
)
}
/*
/**
* Helper for missing modules to determine if name `x.y` is a module `x.y` or
* an attribute `y` of module `x`. This list should be added to as required.
*/
@@ -444,6 +447,7 @@ library class ClassDecl extends @py_object {
this.(ControlFlowNode).getNode() instanceof ClassExpr
}
/** Gets a textual representation of this element. */
string toString() { result = "ClassDecl" }
/** Gets the class scope for Python class declarations */

View File

@@ -195,6 +195,7 @@ private newtype TIterationDefinition =
* A definition of a variable in a for loop `for v in ...:`
*/
deprecated class IterationDefinition extends TIterationDefinition {
/** Gets a textual representation of this element. */
string toString() { result = "IterationDefinition" }
ControlFlowNode getSequence() { this = TIterationDefinition_(_, _, result) }

View File

@@ -28,6 +28,7 @@ private newtype TTInvocation =
* all calls made to a function for a given context.
*/
class FunctionInvocation extends TTInvocation {
/** Gets a textual representation of this element. */
string toString() { result = "Invocation" }
FunctionObject getFunction() { this = TInvocation(result, _) }

View File

@@ -68,6 +68,7 @@ private ClassObjectInternal sole_base(ClassObjectInternal cls) {
/** A list of classes, used to represent the MRO of a class */
class ClassList extends TClassList {
/** Gets a textual representation of this element. */
string toString() { result = "[" + this.contents() + "]" }
string contents() {
@@ -243,6 +244,7 @@ private predicate required_list(ClassList head, ClassListList tail) {
}
private class ClassListList extends TClassListList {
/** Gets a textual representation of this element. */
string toString() { result = "[" + this.contents() + "]" }
string contents() {

View File

@@ -9,6 +9,7 @@ private import semmle.python.types.Extensions
/* Use this version for speed */
library class CfgOrigin extends @py_object {
/** Gets a textual representation of this element. */
string toString() {
/* Not to be displayed */
result = "CfgOrigin"

View File

@@ -129,6 +129,7 @@ module Context {
* * All other contexts are call contexts and consist of a pair of call-site and caller context.
*/
class PointsToContext extends TPointsToContext {
/** Gets a textual representation of this element. */
cached
string toString() {
this = TMainContext() and result = "main"

View File

@@ -17,6 +17,7 @@ class Builtin extends @py_cobject {
)
}
/** Gets a textual representation of this element. */
string toString() {
not this = undefinedVariable().asBuiltin() and
not this = Builtin::unknown() and

View File

@@ -64,20 +64,29 @@ class Object extends @py_object {
private predicate hasOrigin() { py_flow_bb_node(this, _, _, _) }
predicate hasLocationInfo(string filepath, int bl, int bc, int el, int ec) {
this.hasOrigin() and this.getOrigin().getLocation().hasLocationInfo(filepath, bl, bc, el, ec)
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) { this.hasOrigin() and this.getOrigin().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
or
not this.hasOrigin() and
filepath = ":Compiled Code" and
bl = 0 and
bc = 0 and
el = 0 and
ec = 0
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
}
/** INTERNAL -- Do not use */
Builtin asBuiltin() { result = this }
/** Gets a textual representation of this element. */
string toString() {
not this = undefinedVariable() and
not this = unknownValue() and

View File

@@ -63,6 +63,7 @@ class UntrustedCookie extends TaintKind {
}
abstract class CookieOperation extends @py_flow_node {
/** Gets a textual representation of this element. */
abstract string toString();
abstract ControlFlowNode getKey();

View File

@@ -0,0 +1,47 @@
edges
| xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:10:17:10:43 | etree.XML string |
| xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:10:17:10:43 | etree.XML string |
| xslt.py:10:17:10:43 | etree.XML string | xslt.py:11:27:11:35 | etree.XML string |
| xslt.py:10:17:10:43 | etree.XML string | xslt.py:11:27:11:35 | etree.XML string |
| xslt.py:11:17:11:36 | lxml etree xml | xslt.py:14:29:14:37 | lxml etree xml |
| xslt.py:11:17:11:36 | lxml etree xml | xslt.py:14:29:14:37 | lxml etree xml |
| xslt.py:11:27:11:35 | etree.XML string | xslt.py:11:17:11:36 | lxml etree xml |
| xslt.py:11:27:11:35 | etree.XML string | xslt.py:11:17:11:36 | lxml etree xml |
| xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:10:17:10:43 | etree.XML string |
| xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:10:17:10:43 | etree.XML string |
| xsltInjection.py:10:17:10:43 | etree.XML string | xsltInjection.py:11:27:11:35 | etree.XML string |
| xsltInjection.py:10:17:10:43 | etree.XML string | xsltInjection.py:11:27:11:35 | etree.XML string |
| xsltInjection.py:11:17:11:36 | lxml etree xml | xsltInjection.py:12:28:12:36 | lxml etree xml |
| xsltInjection.py:11:17:11:36 | lxml etree xml | xsltInjection.py:12:28:12:36 | lxml etree xml |
| xsltInjection.py:11:27:11:35 | etree.XML string | xsltInjection.py:11:17:11:36 | lxml etree xml |
| xsltInjection.py:11:27:11:35 | etree.XML string | xsltInjection.py:11:17:11:36 | lxml etree xml |
| xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:17:17:17:43 | etree.XML string |
| xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:17:17:17:43 | etree.XML string |
| xsltInjection.py:17:17:17:43 | etree.XML string | xsltInjection.py:18:27:18:35 | etree.XML string |
| xsltInjection.py:17:17:17:43 | etree.XML string | xsltInjection.py:18:27:18:35 | etree.XML string |
| xsltInjection.py:18:17:18:36 | lxml etree xml | xsltInjection.py:21:29:21:37 | lxml etree xml |
| xsltInjection.py:18:17:18:36 | lxml etree xml | xsltInjection.py:21:29:21:37 | lxml etree xml |
| xsltInjection.py:18:27:18:35 | etree.XML string | xsltInjection.py:18:17:18:36 | lxml etree xml |
| xsltInjection.py:18:27:18:35 | etree.XML string | xsltInjection.py:18:17:18:36 | lxml etree xml |
| xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:26:17:26:43 | etree.XML string |
| xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:26:17:26:43 | etree.XML string |
| xsltInjection.py:26:17:26:43 | etree.XML string | xsltInjection.py:27:27:27:35 | etree.XML string |
| xsltInjection.py:26:17:26:43 | etree.XML string | xsltInjection.py:27:27:27:35 | etree.XML string |
| xsltInjection.py:27:17:27:36 | lxml etree xml | xsltInjection.py:31:24:31:32 | lxml etree xml |
| xsltInjection.py:27:17:27:36 | lxml etree xml | xsltInjection.py:31:24:31:32 | lxml etree xml |
| xsltInjection.py:27:27:27:35 | etree.XML string | xsltInjection.py:27:17:27:36 | lxml etree xml |
| xsltInjection.py:27:27:27:35 | etree.XML string | xsltInjection.py:27:17:27:36 | lxml etree xml |
| xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:35:17:35:43 | etree.XML string |
| xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:35:17:35:43 | etree.XML string |
| xsltInjection.py:35:17:35:43 | etree.XML string | xsltInjection.py:36:34:36:42 | etree.XML string |
| xsltInjection.py:35:17:35:43 | etree.XML string | xsltInjection.py:36:34:36:42 | etree.XML string |
| xsltInjection.py:36:17:36:43 | lxml etree xml | xsltInjection.py:40:24:40:32 | lxml etree xml |
| xsltInjection.py:36:17:36:43 | lxml etree xml | xsltInjection.py:40:24:40:32 | lxml etree xml |
| xsltInjection.py:36:34:36:42 | etree.XML string | xsltInjection.py:36:17:36:43 | lxml etree xml |
| xsltInjection.py:36:34:36:42 | etree.XML string | xsltInjection.py:36:17:36:43 | lxml etree xml |
#select
| xslt.py:14:29:14:37 | xslt_root | xslt.py:10:17:10:28 | dict of etree.XML string | xslt.py:14:29:14:37 | lxml etree xml | This XSLT query depends on $@. | xslt.py:10:17:10:28 | Attribute | a user-provided value |
| xsltInjection.py:12:28:12:36 | xslt_root | xsltInjection.py:10:17:10:28 | dict of etree.XML string | xsltInjection.py:12:28:12:36 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:10:17:10:28 | Attribute | a user-provided value |
| xsltInjection.py:21:29:21:37 | xslt_root | xsltInjection.py:17:17:17:28 | dict of etree.XML string | xsltInjection.py:21:29:21:37 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:17:17:17:28 | Attribute | a user-provided value |
| xsltInjection.py:31:24:31:32 | xslt_root | xsltInjection.py:26:17:26:28 | dict of etree.XML string | xsltInjection.py:31:24:31:32 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:26:17:26:28 | Attribute | a user-provided value |
| xsltInjection.py:40:24:40:32 | xslt_root | xsltInjection.py:35:17:35:28 | dict of etree.XML string | xsltInjection.py:40:24:40:32 | lxml etree xml | This XSLT query depends on $@. | xsltInjection.py:35:17:35:28 | Attribute | a user-provided value |

View File

@@ -0,0 +1 @@
experimental/CWE-643/Xslt.ql

View File

@@ -0,0 +1,12 @@
| xslt.py:14:29:14:37 | lxml.etree.parse.xslt | lxml etree xml |
| xsltInjection.py:12:28:12:36 | lxml.etree.XSLT | lxml etree xml |
| xsltInjection.py:21:29:21:37 | lxml.etree.parse.xslt | lxml etree xml |
| xsltInjection.py:31:24:31:32 | lxml.etree.parse.xslt | lxml etree xml |
| xsltInjection.py:40:24:40:32 | lxml.etree.parse.xslt | lxml etree xml |
| xsltInjection.py:50:24:50:32 | lxml.etree.parse.xslt | lxml etree xml |
| xsltInjection.py:60:24:60:32 | lxml.etree.parse.xslt | lxml etree xml |
| xsltInjection.py:69:24:69:32 | lxml.etree.parse.xslt | lxml etree xml |
| xsltInjection.py:79:24:79:32 | lxml.etree.parse.xslt | lxml etree xml |
| xsltSinks.py:17:28:17:36 | lxml.etree.XSLT | lxml etree xml |
| xsltSinks.py:30:29:30:37 | lxml.etree.parse.xslt | lxml etree xml |
| xsltSinks.py:44:24:44:32 | lxml.etree.parse.xslt | lxml etree xml |

View File

@@ -0,0 +1,6 @@
import python
import experimental.semmle.python.security.injection.XSLT
from XSLTInjection::XSLTInjectionSink sink, TaintKind kind
where sink.sinks(kind)
select sink, kind

View File

@@ -0,0 +1 @@
semmle-extractor-options: -p ../../query-tests/Security/lib/ --max-import-depth=3

View File

@@ -0,0 +1,14 @@
from lxml import etree
from io import StringIO
from flask import Flask, request
app = Flask(__name__)
@app.route("/xslt")
def bad():
xsltQuery = request.args.get('xml', '')
xslt_root = etree.XML(xsltQuery)
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result_tree = tree.xslt(xslt_root) # Not OK

View File

@@ -0,0 +1,79 @@
from lxml import etree
from io import StringIO
from flask import Flask, request
app = Flask(__name__)
@app.route("/xslt1")
def a():
xsltQuery = request.args.get('xml', '')
xslt_root = etree.XML(xsltQuery)
transform = etree.XSLT(xslt_root) # Not OK
@app.route("/xslt2")
def b():
xsltQuery = request.args.get('xml', '')
xslt_root = etree.XML(xsltQuery)
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result_tree = tree.xslt(xslt_root) # Not OK
@app.route("/xslt3")
def c():
xsltQuery = request.args.get('xml', '')
xslt_root = etree.XML(xsltQuery)
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result = tree.xslt(xslt_root, a="'A'") # Not OK
@app.route("/xslt4")
def d():
xsltQuery = request.args.get('xml', '')
xslt_root = etree.fromstring(xsltQuery)
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result = tree.xslt(xslt_root, a="'A'") # Not OK
@app.route("/xslt5")
def e():
xsltQuery = request.args.get('xml', '')
xsltStrings = [xsltQuery,"asd","random"]
xslt_root = etree.fromstringlist(xsltStrings)
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result = tree.xslt(xslt_root, a="'A'") # Not OK
@app.route("/xslt6")
def f():
xsltQuery = '<non><remote><query></query></remote></non>'
xslt_root = etree.XML(xsltQuery)
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result = tree.xslt(xslt_root, a="'A'") # OK
@app.route("/xslt7")
def g():
xsltQuery = '<non><remote><query></query></remote></non>'
xslt_root = etree.fromstring(xsltQuery)
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result = tree.xslt(xslt_root, a="'A'") # OK
@app.route("/xslt8")
def h():
xsltQuery = '<non><remote><query></query></remote></non>'
xsltStrings = [xsltQuery,"asd","random"]
xslt_root = etree.fromstringlist(xsltStrings)
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result = tree.xslt(xslt_root, a="'A'") # OK

View File

@@ -0,0 +1,56 @@
from lxml import etree
from io import StringIO
from django.urls import path
from django.http import HttpResponse
from django.template import Template, Context, Engine, engines
def a(request):
xslt_root = etree.XML('''\
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<foo><xsl:value-of select="/a/b/text()" /></foo>
</xsl:template>
</xsl:stylesheet>''')
transform = etree.XSLT(xslt_root)
def b(request):
xslt_root = etree.XML('''\
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<foo><xsl:value-of select="/a/b/text()" /></foo>
</xsl:template>
</xsl:stylesheet>''')
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result_tree = tree.xslt(xslt_root)
def c(request):
xslt_root = etree.XML('''\
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<foo><xsl:value-of select="/a/b/text()" /></foo>
</xsl:template>
</xsl:stylesheet>''')
f = StringIO('<foo><bar></bar></foo>')
tree = etree.parse(f)
result = tree.xslt(xslt_root, a="'A'")
urlpatterns = [
path('a', a),
path('b', b),
path('c', c)
]
if __name__ == "__main__":
a(None)
b(None)
c(None)