Merge branch 'main' of github.com:github/codeql into python/promote-regex-injection

This commit is contained in:
Rasmus Lerchedahl Petersen
2021-09-16 14:50:17 +02:00
629 changed files with 22448 additions and 4670 deletions

View File

@@ -1,9 +1,7 @@
import python
/** A file */
class File extends Container {
File() { files(this, _, _, _, _) }
class File extends Container, @file {
/** DEPRECATED: Use `getAbsolutePath` instead. */
deprecated override string getName() { result = this.getAbsolutePath() }
@@ -34,9 +32,7 @@ class File extends Container {
}
/** Gets a short name for this file (just the file name) */
string getShortName() {
exists(string simple, string ext | files(this, _, simple, ext, _) | result = simple + ext)
}
string getShortName() { result = this.getBaseName() }
private int lastLine() {
result = max(int i | exists(Location l | l.getFile() = this and l.getEndLine() = i))
@@ -55,7 +51,7 @@ class File extends Container {
)
}
override string getAbsolutePath() { files(this, result, _, _, _) }
override string getAbsolutePath() { files(this, result) }
/** Gets the URL of this file. */
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
@@ -118,15 +114,10 @@ private predicate occupied_line(File f, int n) {
}
/** A folder (directory) */
class Folder extends Container {
Folder() { folders(this, _, _) }
class Folder extends Container, @folder {
/** DEPRECATED: Use `getAbsolutePath` instead. */
deprecated override string getName() { result = this.getAbsolutePath() }
/** DEPRECATED: Use `getBaseName` instead. */
deprecated string getSimple() { folders(this, _, result) }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
@@ -144,7 +135,7 @@ class Folder extends Container {
endcolumn = 0
}
override string getAbsolutePath() { folders(this, result, _) }
override string getAbsolutePath() { folders(this, result) }
/** Gets the URL of this folder. */
override string getURL() { result = "folder://" + this.getAbsolutePath() }

View File

@@ -653,6 +653,8 @@ class DefinitionNode extends ControlFlowNode {
DefinitionNode() {
exists(Assign a | a.getATarget().getAFlowNode() = this)
or
exists(AnnAssign a | a.getTarget().getAFlowNode() = this and exists(a.getValue()))
or
exists(Alias a | a.getAsname().getAFlowNode() = this)
or
augstore(_, this)
@@ -795,6 +797,9 @@ private AstNode assigned_value(Expr lhs) {
/* lhs = result */
exists(Assign a | a.getATarget() = lhs and result = a.getValue())
or
/* lhs : annotation = result */
exists(AnnAssign a | a.getTarget() = lhs and result = a.getValue())
or
/* import result as lhs */
exists(Alias a | a.getAsname() = lhs and result = a.getValue())
or

View File

@@ -153,6 +153,12 @@ class ExceptStmt extends ExceptStmt_ {
override Stmt getASubStatement() { result = this.getAStmt() }
override Stmt getLastStatement() { result = this.getBody().getLastItem().getLastStatement() }
override Expr getType() {
result = super.getType() and not result instanceof Tuple
or
result = super.getType().(Tuple).getAnElt()
}
}
/** An assert statement, such as `assert a == b, "A is not equal to b"` */

View File

@@ -3690,8 +3690,8 @@ private module Subpaths {
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
arg.getASuccessor() = par and
arg.getASuccessor() = out and
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and

View File

@@ -3690,8 +3690,8 @@ private module Subpaths {
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
arg.getASuccessor() = par and
arg.getASuccessor() = out and
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and

View File

@@ -3690,8 +3690,8 @@ private module Subpaths {
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
arg.getASuccessor() = par and
arg.getASuccessor() = out and
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and

View File

@@ -3690,8 +3690,8 @@ private module Subpaths {
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
arg.getASuccessor() = par and
arg.getASuccessor() = out and
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
par.getNodeEx() = p and
out.getNodeEx() = o and

View File

@@ -869,6 +869,9 @@ predicate jumpStep(Node nodeFrom, Node nodeTo) {
module_export(mv.getScope(), r.getAttributeName(), nodeFrom) and
nodeTo = r
)
or
// Default value for parameter flows to that parameter
defaultValueFlowStep(nodeFrom, nodeTo)
}
/**
@@ -1033,6 +1036,19 @@ predicate kwOverflowStoreStep(CfgNode nodeFrom, DictionaryElementContent c, Node
)
}
predicate defaultValueFlowStep(CfgNode nodeFrom, CfgNode nodeTo) {
exists(Function f, Parameter p, ParameterDefinition def |
// `getArgByName` supports, unlike `getAnArg`, keyword-only parameters
p = f.getArgByName(_) and
nodeFrom.asExpr() = p.getDefault() and
// The following expresses
// nodeTo.(ParameterNode).getParameter() = p
// without non-monotonic recursion
def.getParameter() = p and
nodeTo.getNode() = def.getDefiningNode()
)
}
/**
* Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`.
*/

View File

@@ -773,15 +773,18 @@ abstract class RegexString extends Expr {
* string is empty.
*/
predicate multiples(int start, int end, string lower, string upper) {
this.getChar(start) = "{" and
this.getChar(end - 1) = "}" and
exists(string inner | inner = this.getText().substring(start + 1, end - 1) |
inner.regexpMatch("[0-9]+") and
exists(string text, string match, string inner |
text = this.getText() and
end = start + match.length() and
inner = match.substring(1, match.length() - 1)
|
match = text.regexpFind("\\{[0-9]+\\}", _, start) and
lower = inner and
upper = lower
or
inner.regexpMatch("[0-9]*,[0-9]*") and
exists(int commaIndex | commaIndex = inner.indexOf(",") |
match = text.regexpFind("\\{[0-9]*,[0-9]*\\}", _, start) and
exists(int commaIndex |
commaIndex = inner.indexOf(",") and
lower = inner.prefix(commaIndex) and
upper = inner.suffix(commaIndex + 1)
)

View File

@@ -120,16 +120,11 @@ svnchurn(
Python dbscheme
****************************/
/* fromSource is ignored */
files(unique int id: @file,
varchar(900) name: string ref,
varchar(900) simple: string ref,
varchar(900) ext: string ref,
int fromSource: int ref);
varchar(900) name: string ref);
folders(unique int id: @folder,
varchar(900) name: string ref,
varchar(900) simple: string ref);
varchar(900) name: string ref);
@container = @folder | @file;

View File

@@ -4331,18 +4331,6 @@
<k>name</k>
<v>3066</v>
</e>
<e>
<k>simple</k>
<v>1294</v>
</e>
<e>
<k>ext</k>
<v>1</v>
</e>
<e>
<k>fromSource</k>
<v>1</v>
</e>
</columnsizes>
<dependencies>
<dep>
@@ -4362,54 +4350,6 @@
</val>
</dep>
<dep>
<src>id</src>
<trg>simple</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>3066</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>id</src>
<trg>ext</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>3066</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>id</src>
<trg>fromSource</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>3066</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>name</src>
<trg>id</trg>
<val>
@@ -4425,276 +4365,6 @@
</hist>
</val>
</dep>
<dep>
<src>name</src>
<trg>simple</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>3066</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>name</src>
<trg>ext</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>3066</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>name</src>
<trg>fromSource</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>3066</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>simple</src>
<trg>id</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>1058</v>
</b>
<b>
<a>2</a>
<b>3</b>
<v>132</v>
</b>
<b>
<a>3</a>
<b>38</b>
<v>98</v>
</b>
<b>
<a>47</a>
<b>646</b>
<v>6</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>simple</src>
<trg>name</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>1058</v>
</b>
<b>
<a>2</a>
<b>3</b>
<v>132</v>
</b>
<b>
<a>3</a>
<b>38</b>
<v>98</v>
</b>
<b>
<a>47</a>
<b>646</b>
<v>6</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>simple</src>
<trg>ext</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>1294</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>simple</src>
<trg>fromSource</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>1294</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>ext</src>
<trg>id</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>3066</a>
<b>3067</b>
<v>1</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>ext</src>
<trg>name</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>3066</a>
<b>3067</b>
<v>1</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>ext</src>
<trg>simple</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1294</a>
<b>1295</b>
<v>1</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>ext</src>
<trg>fromSource</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>1</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>fromSource</src>
<trg>id</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>3066</a>
<b>3067</b>
<v>1</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>fromSource</src>
<trg>name</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>3066</a>
<b>3067</b>
<v>1</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>fromSource</src>
<trg>simple</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1294</a>
<b>1295</b>
<v>1</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>fromSource</src>
<trg>ext</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>1</v>
</b>
</bs>
</hist>
</val>
</dep>
</dependencies>
</relation>
<relation>
@@ -4709,10 +4379,6 @@
<k>name</k>
<v>686</v>
</e>
<e>
<k>simple</k>
<v>538</v>
</e>
</columnsizes>
<dependencies>
<dep>
@@ -4732,22 +4398,6 @@
</val>
</dep>
<dep>
<src>id</src>
<trg>simple</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>686</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>name</src>
<trg>id</trg>
<val>
@@ -4763,74 +4413,6 @@
</hist>
</val>
</dep>
<dep>
<src>name</src>
<trg>simple</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>686</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>simple</src>
<trg>id</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>481</v>
</b>
<b>
<a>2</a>
<b>4</b>
<v>45</v>
</b>
<b>
<a>4</a>
<b>27</b>
<v>12</v>
</b>
</bs>
</hist>
</val>
</dep>
<dep>
<src>simple</src>
<trg>name</trg>
<val>
<hist>
<budget>12</budget>
<bs>
<b>
<a>1</a>
<b>2</b>
<v>481</v>
</b>
<b>
<a>2</a>
<b>4</b>
<v>45</v>
</b>
<b>
<a>4</a>
<b>27</b>
<v>12</v>
</b>
</bs>
</hist>
</val>
</dep>
</dependencies>
</relation>
<relation>

View File

@@ -30,5 +30,11 @@ predicate modification_of_locals(ControlFlowNode f) {
}
from AstNode a, ControlFlowNode f
where modification_of_locals(f) and a = f.getNode()
where
modification_of_locals(f) and
a = f.getNode() and
// in module level scope `locals() == globals()`
// see https://docs.python.org/3/library/functions.html#locals
// FP report in https://github.com/github/codeql/issues/6674
not a.getScope() instanceof ModuleScope
select a, "Modification of the locals() dictionary will have no effect on the local variables."

View File

@@ -19,6 +19,7 @@ predicate unused_local(Name unused, LocalVariable v) {
def.getVariable() = v and
def.isUnused() and
not exists(def.getARedef()) and
not exists(annotation_without_assignment(v)) and
def.isRelevant() and
not v = any(Nonlocal n).getAVariable() and
not exists(def.getNode().getParentNode().(FunctionDef).getDefinedFunction().getADecorator()) and
@@ -26,6 +27,17 @@ predicate unused_local(Name unused, LocalVariable v) {
)
}
/**
* Gets any annotation of the local variable `v` that does not also reassign its value.
*
* TODO: This predicate should not be needed. Rather, annotated "assignments" that do not actually
* assign a value should not result in the creation of an SSA variable (which then goes unused).
*/
private AnnAssign annotation_without_assignment(LocalVariable v) {
result.getTarget() = v.getAStore() and
not exists(result.getValue())
}
from Name unused, LocalVariable v
where
unused_local(unused, v) and

View File

@@ -66,9 +66,9 @@ def argument_passing(
b,
/,
c,
d=arg4,
d=arg4, #$ arg4 func=argument_passing
*,
e=arg5,
e=arg5, #$ arg5 func=argument_passing
f,
**g,
):
@@ -120,7 +120,7 @@ def test_multiple_kw_args():
with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ arg1 arg2 arg3 func=with_multiple_kw_args
def with_default_arguments(a=arg1, b=arg2, c=arg3): # Need a mechanism to test default arguments
def with_default_arguments(a=arg1, b=arg2, c=arg3): #$ arg1 arg2 arg3 func=with_default_arguments
SINK1(a)
SINK2(b)
SINK3(c)

View File

@@ -14,6 +14,8 @@ edges
| argumentPassing.py:120:59:120:69 | ControlFlowNode for Dict [Dictionary element at key a] | argumentPassing.py:120:5:120:70 | KwUnpacked a |
| argumentPassing.py:120:65:120:68 | ControlFlowNode for arg1 | argumentPassing.py:120:59:120:69 | ControlFlowNode for Dict [Dictionary element at key a] |
| argumentPassing.py:123:28:123:28 | ControlFlowNode for a | argumentPassing.py:124:11:124:11 | ControlFlowNode for a |
| argumentPassing.py:123:28:123:28 | ControlFlowNode for a | argumentPassing.py:124:11:124:11 | ControlFlowNode for a |
| argumentPassing.py:123:30:123:33 | ControlFlowNode for arg1 | argumentPassing.py:123:28:123:28 | ControlFlowNode for a |
| argumentPassing.py:132:28:132:31 | ControlFlowNode for arg1 | argumentPassing.py:123:28:123:28 | ControlFlowNode for a |
| argumentPassing.py:138:22:138:24 | ControlFlowNode for foo | argumentPassing.py:139:11:139:13 | ControlFlowNode for foo |
| argumentPassing.py:160:46:160:49 | ControlFlowNode for arg1 | argumentPassing.py:138:22:138:24 | ControlFlowNode for foo |
@@ -102,6 +104,8 @@ nodes
| argumentPassing.py:120:59:120:69 | ControlFlowNode for Dict [Dictionary element at key a] | semmle.label | ControlFlowNode for Dict [Dictionary element at key a] |
| argumentPassing.py:120:65:120:68 | ControlFlowNode for arg1 | semmle.label | ControlFlowNode for arg1 |
| argumentPassing.py:123:28:123:28 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| argumentPassing.py:123:28:123:28 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| argumentPassing.py:123:30:123:33 | ControlFlowNode for arg1 | semmle.label | ControlFlowNode for arg1 |
| argumentPassing.py:124:11:124:11 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| argumentPassing.py:132:28:132:31 | ControlFlowNode for arg1 | semmle.label | ControlFlowNode for arg1 |
| argumentPassing.py:138:22:138:24 | ControlFlowNode for foo | semmle.label | ControlFlowNode for foo |
@@ -207,6 +211,7 @@ subpaths
| argumentPassing.py:118:27:118:30 | ControlFlowNode for arg1 | argumentPassing.py:118:27:118:30 | ControlFlowNode for arg1 | argumentPassing.py:110:11:110:11 | ControlFlowNode for a | Flow found |
| argumentPassing.py:119:27:119:30 | ControlFlowNode for arg1 | argumentPassing.py:119:27:119:30 | ControlFlowNode for arg1 | argumentPassing.py:110:11:110:11 | ControlFlowNode for a | Flow found |
| argumentPassing.py:120:65:120:68 | ControlFlowNode for arg1 | argumentPassing.py:120:65:120:68 | ControlFlowNode for arg1 | argumentPassing.py:110:11:110:11 | ControlFlowNode for a | Flow found |
| argumentPassing.py:123:30:123:33 | ControlFlowNode for arg1 | argumentPassing.py:123:30:123:33 | ControlFlowNode for arg1 | argumentPassing.py:124:11:124:11 | ControlFlowNode for a | Flow found |
| argumentPassing.py:132:28:132:31 | ControlFlowNode for arg1 | argumentPassing.py:132:28:132:31 | ControlFlowNode for arg1 | argumentPassing.py:124:11:124:11 | ControlFlowNode for a | Flow found |
| argumentPassing.py:160:46:160:49 | ControlFlowNode for arg1 | argumentPassing.py:160:46:160:49 | ControlFlowNode for arg1 | argumentPassing.py:139:11:139:13 | ControlFlowNode for foo | Flow found |
| argumentPassing.py:168:14:168:17 | ControlFlowNode for arg1 | argumentPassing.py:168:14:168:17 | ControlFlowNode for arg1 | argumentPassing.py:166:15:166:15 | ControlFlowNode for a | Flow found |

View File

@@ -10,6 +10,8 @@ edges
| argumentPassing.py:120:29:120:39 | ControlFlowNode for Dict [Dictionary element at key b] | argumentPassing.py:120:5:120:70 | KwUnpacked b |
| argumentPassing.py:120:35:120:38 | ControlFlowNode for arg2 | argumentPassing.py:120:29:120:39 | ControlFlowNode for Dict [Dictionary element at key b] |
| argumentPassing.py:123:36:123:36 | ControlFlowNode for b | argumentPassing.py:125:11:125:11 | ControlFlowNode for b |
| argumentPassing.py:123:36:123:36 | ControlFlowNode for b | argumentPassing.py:125:11:125:11 | ControlFlowNode for b |
| argumentPassing.py:123:38:123:41 | ControlFlowNode for arg2 | argumentPassing.py:123:36:123:36 | ControlFlowNode for b |
| argumentPassing.py:133:30:133:33 | ControlFlowNode for arg2 | argumentPassing.py:123:36:123:36 | ControlFlowNode for b |
| argumentPassing.py:138:29:138:34 | ControlFlowNode for kwargs [Dictionary element at key bar] | argumentPassing.py:140:20:140:25 | ControlFlowNode for kwargs [Dictionary element at key bar] |
| argumentPassing.py:140:5:140:26 | KwUnpacked bar | argumentPassing.py:145:18:145:20 | ControlFlowNode for bar |
@@ -64,6 +66,8 @@ nodes
| argumentPassing.py:120:29:120:39 | ControlFlowNode for Dict [Dictionary element at key b] | semmle.label | ControlFlowNode for Dict [Dictionary element at key b] |
| argumentPassing.py:120:35:120:38 | ControlFlowNode for arg2 | semmle.label | ControlFlowNode for arg2 |
| argumentPassing.py:123:36:123:36 | ControlFlowNode for b | semmle.label | ControlFlowNode for b |
| argumentPassing.py:123:36:123:36 | ControlFlowNode for b | semmle.label | ControlFlowNode for b |
| argumentPassing.py:123:38:123:41 | ControlFlowNode for arg2 | semmle.label | ControlFlowNode for arg2 |
| argumentPassing.py:125:11:125:11 | ControlFlowNode for b | semmle.label | ControlFlowNode for b |
| argumentPassing.py:133:30:133:33 | ControlFlowNode for arg2 | semmle.label | ControlFlowNode for arg2 |
| argumentPassing.py:138:29:138:34 | ControlFlowNode for kwargs [Dictionary element at key bar] | semmle.label | ControlFlowNode for kwargs [Dictionary element at key bar] |
@@ -128,6 +132,7 @@ subpaths
| argumentPassing.py:105:27:105:30 | ControlFlowNode for arg2 | argumentPassing.py:105:27:105:30 | ControlFlowNode for arg2 | argumentPassing.py:99:11:99:11 | ControlFlowNode for b | Flow found |
| argumentPassing.py:117:29:117:32 | ControlFlowNode for arg2 | argumentPassing.py:117:29:117:32 | ControlFlowNode for arg2 | argumentPassing.py:111:11:111:11 | ControlFlowNode for b | Flow found |
| argumentPassing.py:120:35:120:38 | ControlFlowNode for arg2 | argumentPassing.py:120:35:120:38 | ControlFlowNode for arg2 | argumentPassing.py:111:11:111:11 | ControlFlowNode for b | Flow found |
| argumentPassing.py:123:38:123:41 | ControlFlowNode for arg2 | argumentPassing.py:123:38:123:41 | ControlFlowNode for arg2 | argumentPassing.py:125:11:125:11 | ControlFlowNode for b | Flow found |
| argumentPassing.py:133:30:133:33 | ControlFlowNode for arg2 | argumentPassing.py:133:30:133:33 | ControlFlowNode for arg2 | argumentPassing.py:125:11:125:11 | ControlFlowNode for b | Flow found |
| argumentPassing.py:160:36:160:39 | ControlFlowNode for arg2 | argumentPassing.py:160:36:160:39 | ControlFlowNode for arg2 | argumentPassing.py:146:11:146:13 | ControlFlowNode for bar | Flow found |
| classes.py:565:18:565:21 | ControlFlowNode for arg2 | classes.py:565:18:565:21 | ControlFlowNode for arg2 | classes.py:556:15:556:17 | ControlFlowNode for key | Flow found |

View File

@@ -10,6 +10,8 @@ edges
| argumentPassing.py:120:44:120:54 | ControlFlowNode for Dict [Dictionary element at key c] | argumentPassing.py:120:5:120:70 | KwUnpacked c |
| argumentPassing.py:120:50:120:53 | ControlFlowNode for arg3 | argumentPassing.py:120:44:120:54 | ControlFlowNode for Dict [Dictionary element at key c] |
| argumentPassing.py:123:44:123:44 | ControlFlowNode for c | argumentPassing.py:126:11:126:11 | ControlFlowNode for c |
| argumentPassing.py:123:44:123:44 | ControlFlowNode for c | argumentPassing.py:126:11:126:11 | ControlFlowNode for c |
| argumentPassing.py:123:46:123:49 | ControlFlowNode for arg3 | argumentPassing.py:123:44:123:44 | ControlFlowNode for c |
| argumentPassing.py:134:5:134:41 | KwUnpacked c | argumentPassing.py:123:44:123:44 | ControlFlowNode for c |
| argumentPassing.py:134:30:134:40 | ControlFlowNode for Dict [Dictionary element at key c] | argumentPassing.py:134:5:134:41 | KwUnpacked c |
| argumentPassing.py:134:36:134:39 | ControlFlowNode for arg3 | argumentPassing.py:134:30:134:40 | ControlFlowNode for Dict [Dictionary element at key c] |
@@ -37,6 +39,8 @@ nodes
| argumentPassing.py:120:44:120:54 | ControlFlowNode for Dict [Dictionary element at key c] | semmle.label | ControlFlowNode for Dict [Dictionary element at key c] |
| argumentPassing.py:120:50:120:53 | ControlFlowNode for arg3 | semmle.label | ControlFlowNode for arg3 |
| argumentPassing.py:123:44:123:44 | ControlFlowNode for c | semmle.label | ControlFlowNode for c |
| argumentPassing.py:123:44:123:44 | ControlFlowNode for c | semmle.label | ControlFlowNode for c |
| argumentPassing.py:123:46:123:49 | ControlFlowNode for arg3 | semmle.label | ControlFlowNode for arg3 |
| argumentPassing.py:126:11:126:11 | ControlFlowNode for c | semmle.label | ControlFlowNode for c |
| argumentPassing.py:134:5:134:41 | KwUnpacked c | semmle.label | KwUnpacked c |
| argumentPassing.py:134:30:134:40 | ControlFlowNode for Dict [Dictionary element at key c] | semmle.label | ControlFlowNode for Dict [Dictionary element at key c] |
@@ -59,6 +63,7 @@ subpaths
| argumentPassing.py:117:37:117:40 | ControlFlowNode for arg3 | argumentPassing.py:117:37:117:40 | ControlFlowNode for arg3 | argumentPassing.py:112:11:112:11 | ControlFlowNode for c | Flow found |
| argumentPassing.py:119:41:119:44 | ControlFlowNode for arg3 | argumentPassing.py:119:41:119:44 | ControlFlowNode for arg3 | argumentPassing.py:112:11:112:11 | ControlFlowNode for c | Flow found |
| argumentPassing.py:120:50:120:53 | ControlFlowNode for arg3 | argumentPassing.py:120:50:120:53 | ControlFlowNode for arg3 | argumentPassing.py:112:11:112:11 | ControlFlowNode for c | Flow found |
| argumentPassing.py:123:46:123:49 | ControlFlowNode for arg3 | argumentPassing.py:123:46:123:49 | ControlFlowNode for arg3 | argumentPassing.py:126:11:126:11 | ControlFlowNode for c | Flow found |
| argumentPassing.py:134:36:134:39 | ControlFlowNode for arg3 | argumentPassing.py:134:36:134:39 | ControlFlowNode for arg3 | argumentPassing.py:126:11:126:11 | ControlFlowNode for c | Flow found |
| argumentPassing.py:160:26:160:29 | ControlFlowNode for arg3 | argumentPassing.py:160:26:160:29 | ControlFlowNode for arg3 | argumentPassing.py:155:11:155:13 | ControlFlowNode for baz | Flow found |
| classes.py:581:26:581:29 | ControlFlowNode for arg3 | classes.py:581:26:581:29 | ControlFlowNode for arg3 | classes.py:571:15:571:19 | ControlFlowNode for value | Flow found |

View File

@@ -1,4 +1,10 @@
edges
| argumentPassing.py:69:5:69:5 | ControlFlowNode for d | argumentPassing.py:78:11:78:11 | ControlFlowNode for d |
| argumentPassing.py:69:7:69:10 | ControlFlowNode for arg4 | argumentPassing.py:69:5:69:5 | ControlFlowNode for d |
nodes
| argumentPassing.py:69:5:69:5 | ControlFlowNode for d | semmle.label | ControlFlowNode for d |
| argumentPassing.py:69:7:69:10 | ControlFlowNode for arg4 | semmle.label | ControlFlowNode for arg4 |
| argumentPassing.py:78:11:78:11 | ControlFlowNode for d | semmle.label | ControlFlowNode for d |
subpaths
#select
| argumentPassing.py:69:7:69:10 | ControlFlowNode for arg4 | argumentPassing.py:69:7:69:10 | ControlFlowNode for arg4 | argumentPassing.py:78:11:78:11 | ControlFlowNode for d | Flow found |

View File

@@ -1,4 +1,10 @@
edges
| argumentPassing.py:71:5:71:5 | ControlFlowNode for e | argumentPassing.py:79:11:79:11 | ControlFlowNode for e |
| argumentPassing.py:71:7:71:10 | ControlFlowNode for arg5 | argumentPassing.py:71:5:71:5 | ControlFlowNode for e |
nodes
| argumentPassing.py:71:5:71:5 | ControlFlowNode for e | semmle.label | ControlFlowNode for e |
| argumentPassing.py:71:7:71:10 | ControlFlowNode for arg5 | semmle.label | ControlFlowNode for arg5 |
| argumentPassing.py:79:11:79:11 | ControlFlowNode for e | semmle.label | ControlFlowNode for e |
subpaths
#select
| argumentPassing.py:71:7:71:10 | ControlFlowNode for arg5 | argumentPassing.py:71:7:71:10 | ControlFlowNode for arg5 | argumentPassing.py:79:11:79:11 | ControlFlowNode for e | Flow found |

View File

@@ -379,6 +379,12 @@ edges
| test.py:686:43:686:48 | ControlFlowNode for SOURCE | test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 0] |
| test.py:686:51:686:51 | ControlFlowNode for s | test.py:686:3:686:52 | PosOverflowNode for iterate_star_args() [Tuple element at index 1] |
| test.py:757:16:757:21 | ControlFlowNode for SOURCE | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() |
| test.py:795:35:795:35 | ControlFlowNode for x | test.py:796:10:796:10 | ControlFlowNode for x |
| test.py:795:37:795:42 | ControlFlowNode for SOURCE | test.py:795:35:795:35 | ControlFlowNode for x |
| test.py:795:48:795:48 | ControlFlowNode for y | test.py:797:10:797:10 | ControlFlowNode for y |
| test.py:795:50:795:55 | ControlFlowNode for SOURCE | test.py:795:48:795:48 | ControlFlowNode for y |
| test.py:795:61:795:61 | ControlFlowNode for z | test.py:798:10:798:10 | ControlFlowNode for z |
| test.py:795:63:795:68 | ControlFlowNode for SOURCE | test.py:795:61:795:61 | ControlFlowNode for z |
nodes
| datamodel.py:35:7:35:7 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| datamodel.py:36:10:36:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
@@ -818,6 +824,15 @@ nodes
| test.py:686:51:686:51 | ControlFlowNode for s | semmle.label | ControlFlowNode for s |
| test.py:757:16:757:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() |
| test.py:795:35:795:35 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
| test.py:795:37:795:42 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:795:48:795:48 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
| test.py:795:50:795:55 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:795:61:795:61 | ControlFlowNode for z | semmle.label | ControlFlowNode for z |
| test.py:795:63:795:68 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:796:10:796:10 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
| test.py:797:10:797:10 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
| test.py:798:10:798:10 | ControlFlowNode for z | semmle.label | ControlFlowNode for z |
subpaths
| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:35:7:35:7 | ControlFlowNode for a | datamodel.py:36:10:36:10 | ControlFlowNode for a | datamodel.py:38:6:38:17 | ControlFlowNode for f() |
| datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:44:22:44:22 | ControlFlowNode for x | datamodel.py:46:16:46:16 | ControlFlowNode for x | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() |
@@ -942,3 +957,6 @@ subpaths
| test.py:680:10:680:12 | ControlFlowNode for arg | test.py:685:7:685:12 | ControlFlowNode for SOURCE | test.py:680:10:680:12 | ControlFlowNode for arg | Flow found |
| test.py:680:10:680:12 | ControlFlowNode for arg | test.py:686:43:686:48 | ControlFlowNode for SOURCE | test.py:680:10:680:12 | ControlFlowNode for arg | Flow found |
| test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | test.py:757:16:757:21 | ControlFlowNode for SOURCE | test.py:760:10:760:36 | ControlFlowNode for return_from_inner_scope() | Flow found |
| test.py:796:10:796:10 | ControlFlowNode for x | test.py:795:37:795:42 | ControlFlowNode for SOURCE | test.py:796:10:796:10 | ControlFlowNode for x | Flow found |
| test.py:797:10:797:10 | ControlFlowNode for y | test.py:795:50:795:55 | ControlFlowNode for SOURCE | test.py:797:10:797:10 | ControlFlowNode for y | Flow found |
| test.py:798:10:798:10 | ControlFlowNode for z | test.py:795:63:795:68 | ControlFlowNode for SOURCE | test.py:798:10:798:10 | ControlFlowNode for z | Flow found |

View File

@@ -793,6 +793,6 @@ def test_reverse_read_subscript_cls():
@expects(3)
def test_with_default_param_value(x=SOURCE, /, y=SOURCE, *, z=SOURCE):
SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x"
SINK(y) #$ MISSING:flow="SOURCE, l:-2 -> y"
SINK(z) #$ MISSING:flow="SOURCE, l:-3 -> z"
SINK(x) #$ flow="SOURCE, l:-1 -> x"
SINK(y) #$ flow="SOURCE, l:-2 -> y"
SINK(z) #$ flow="SOURCE, l:-3 -> z"

View File

@@ -1,7 +1,5 @@
| code/h_classes.py:3:1:3:16 | ControlFlowNode for ClassExpr | code/h_classes.py:10:1:10:9 | ControlFlowNode for type() |
| code/h_classes.py:3:1:3:16 | ControlFlowNode for ClassExpr | code/h_classes.py:15:5:15:13 | ControlFlowNode for type() |
| code/l_calls.py:3:13:3:14 | ControlFlowNode for List | code/l_calls.py:4:12:4:12 | ControlFlowNode for x |
| code/l_calls.py:6:13:6:14 | ControlFlowNode for List | code/l_calls.py:7:16:7:16 | ControlFlowNode for x |
| code/l_calls.py:12:1:12:20 | ControlFlowNode for ClassExpr | code/l_calls.py:16:16:16:18 | ControlFlowNode for cls |
| code/l_calls.py:12:1:12:20 | ControlFlowNode for ClassExpr | code/l_calls.py:24:13:24:22 | ControlFlowNode for Attribute() |
| code/l_calls.py:12:1:12:20 | ControlFlowNode for ClassExpr | code/l_calls.py:25:16:25:16 | ControlFlowNode for a |

View File

@@ -53,3 +53,12 @@ def ok5(seq):
def ok6(seq):
yield next(iter([]), default='foo')
# Handling for multiple exception types, one of which is `StopIteration`
# Reported as a false positive in github/codeql#6227
def ok7(seq, ctx):
try:
with ctx:
yield next(iter)
except (StopIteration, MemoryError):
return

View File

@@ -1,4 +1,4 @@
| test.py:109:5:109:8 | cond | Parenthesized condition in 'if' statement. |
| test.py:112:8:112:11 | cond | Parenthesized condition in 'while' statement. |
| test.py:115:9:115:12 | test | Parenthesized test in 'assert' statement. |
| test.py:118:13:118:13 | x | Parenthesized value in 'return' statement. |
| test.py:115:5:115:8 | cond | Parenthesized condition in 'if' statement. |
| test.py:118:8:118:11 | cond | Parenthesized condition in 'while' statement. |
| test.py:121:9:121:12 | test | Parenthesized test in 'assert' statement. |
| test.py:124:13:124:13 | x | Parenthesized value in 'return' statement. |

View File

@@ -1 +1 @@
| test.py:162:9:162:17 | Attribute() | Instance of context-manager class $@ is closed in a finally block. Consider using 'with' statement. | test.py:145:1:145:17 | class CM | CM |
| test.py:168:9:168:17 | Attribute() | Instance of context-manager class $@ is closed in a finally block. Consider using 'with' statement. | test.py:151:1:151:17 | class CM | CM |

View File

@@ -18,7 +18,7 @@ def return_in_finally(seq, x):
finally:
return 1
return 0
#Break in loop in finally
#This is OK
def return_in_loop_in_finally(f, seq):
@@ -27,7 +27,7 @@ def return_in_loop_in_finally(f, seq):
finally:
for i in seq:
break
#But this is not
def return_in_loop_in_finally(f, seq):
try:
@@ -49,7 +49,7 @@ class NonIterator(object):
for x in NonIterator():
do_something(x)
#None in for loop
def dodgy_iter(x):
@@ -91,8 +91,8 @@ for z in D():
def modification_of_locals():
x = 0
locals()['x'] = 1
@@ -104,6 +104,12 @@ def modification_of_locals():
return x
globals()['foo'] = 42 # OK
# in module-level scope `locals() == globals()`
# FP report from https://github.com/github/codeql/issues/6674
locals()['foo'] = 43 # technically OK
#C-style things
if (cond):
@@ -128,7 +134,7 @@ class classproperty(object):
return self.getter(instance_type)
class WithClassProperty(object):
@classproperty
def x(self):
return [0]
@@ -143,13 +149,13 @@ for i in WithClassProperty.x:
#Should use context mamager
class CM(object):
def __enter__(self):
pass
def __exit__(self, ex, cls, tb):
pass
def write(self, data):
pass
@@ -168,4 +174,3 @@ def assert_ok(seq):
# False positive. ODASA-8042. Fixed in PR #2401.
class false_positive:
e = (x for x in [])

View File

@@ -288,3 +288,8 @@ def avoid_redundant_split(a):
var = False
if var:
foo.bar() #foo is defined here.
def type_annotation_fp():
annotated : annotation = [1,2,3]
for x in annotated:
print(x)

View File

@@ -1,4 +1,3 @@
| type_annotation_fp.py:5:5:5:7 | foo | The value assigned to local variable 'foo' is never used. |
| variables_test.py:29:5:29:5 | x | The value assigned to local variable 'x' is never used. |
| variables_test.py:89:5:89:5 | a | The value assigned to local variable 'a' is never used. |
| variables_test.py:89:7:89:7 | b | The value assigned to local variable 'b' is never used. |

View File

@@ -9,3 +9,8 @@ def type_annotation(x):
else:
foo : float
do_other_stuff_with(foo)
def type_annotation_fn():
# False negative: the value of `bar` is never used, but this is masked by the presence of the type annotation.
bar = 5
bar : int