Python: Recognize nested tuple/list assignment

Now we recognize `[(x,y)] = [(1,2)]` -- in itself not a widely used idiom, but
more of a warmup excersize for me
This commit is contained in:
Rasmus Wriedt Larsen
2020-01-24 15:07:17 +01:00
parent 9763ec71fe
commit fa48fb04f5
5 changed files with 46 additions and 11 deletions

View File

@@ -753,9 +753,8 @@ class DefinitionNode extends ControlFlowNode {
or
augstore(_, this)
or
exists(Assign a | a.getATarget().(Tuple).getAnElt().getAFlowNode() = this)
or
exists(Assign a | a.getATarget().(List).getAnElt().getAFlowNode() = this)
// `x, y = 1, 2` where LHS is a combination of list or tuples
exists(Assign a | list_or_tuple_nested_element(a.getATarget()).getAFlowNode() = this)
or
exists(For for | for.getTarget().getAFlowNode() = this)
}
@@ -768,6 +767,18 @@ class DefinitionNode extends ControlFlowNode {
}
}
private Expr list_or_tuple_nested_element(Expr list_or_tuple) {
exists(Expr elt |
elt = list_or_tuple.(Tuple).getAnElt()
or
elt = list_or_tuple.(List).getAnElt()
|
result = elt
or
result = list_or_tuple_nested_element(elt)
)
}
/** A control flow node corresponding to a deletion statement, such as `del x`.
* There can be multiple `DeletionNode`s for each `Delete` such that each
* target has own `DeletionNode`. The CFG for `del a, x.y` looks like:
@@ -887,18 +898,38 @@ private AstNode assigned_value(Expr lhs) {
/* lhs += x => result = (lhs + x) */
exists(AugAssign a, BinaryExpr b | b = a.getOperation() and result = b and lhs = b.getLeft())
or
/* ..., lhs, ... = ..., result, ... */
exists(Assign a, Tuple target, Tuple values, int index |
a.getATarget() = target and
a.getValue() = values and
lhs = target.getElt(index) and
result = values.getElt(index)
)
/* ..., lhs, ... = ..., result, ...
* or
* ..., (..., lhs, ...), ... = ..., (..., result, ...), ...
*/
exists(Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result))
or
/* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */
result.(For).getTarget() = lhs
}
predicate nested_sequence_assign(Expr left_parent, Expr right_parent,
Expr left_result, Expr right_result) {
exists(int i, Expr left_elem, Expr right_elem
|
(
left_elem = left_parent.(Tuple).getElt(i)
or
left_elem = left_parent.(List).getElt(i)
)
and
(
right_elem = right_parent.(Tuple).getElt(i)
or
right_elem = right_parent.(List).getElt(i)
)
|
left_result = left_elem and right_result = right_elem
or
nested_sequence_assign(left_elem, right_elem, left_result, right_result)
)
}
/** A flow node for a `for` statement. */
class ForNode extends ControlFlowNode {

View File

@@ -1,5 +1,6 @@
| assignment.py:5 | SOURCE | assignment.py:5 | Taint simple.test | a |
| assignment.py:7 | a | assignment.py:7 | Taint simple.test | b |
| assignment.py:13 | SOURCE | assignment.py:13 | Taint simple.test | t1 |
| assignment.py:13 | SOURCE | assignment.py:13 | Taint simple.test | t2 |
| carrier.py:4 | ParameterDefinition | carrier.py:4 | Taint explicit.carrier | arg |
| carrier.py:4 | ParameterDefinition | carrier.py:4 | Taint simple.test | arg |

View File

@@ -119,6 +119,7 @@
| simple.test | assignment.py:7 | a | | --> | sequence of simple.test | assignment.py:7 | Tuple | |
| simple.test | assignment.py:7 | a | | --> | simple.test | assignment.py:8 | b | |
| simple.test | assignment.py:13 | SOURCE | | --> | sequence of simple.test | assignment.py:13 | Tuple | |
| simple.test | assignment.py:13 | SOURCE | | --> | simple.test | assignment.py:14 | t1 | |
| simple.test | assignment.py:13 | SOURCE | | --> | simple.test | assignment.py:14 | t2 | |
| simple.test | carrier.py:4 | arg | p1 = simple.test | --> | simple.test | carrier.py:5 | arg | p1 = simple.test |
| simple.test | carrier.py:17 | SOURCE | | --> | .attr = simple.test | carrier.py:17 | ImplicitCarrier() | |

View File

@@ -4,5 +4,5 @@
| assignment.py:8 | swap_taint | b | simple.test |
| assignment.py:14 | nested_assignment | s1 | NO TAINT |
| assignment.py:14 | nested_assignment | s2 | NO TAINT |
| assignment.py:14 | nested_assignment | t1 | NO TAINT |
| assignment.py:14 | nested_assignment | t1 | simple.test |
| assignment.py:14 | nested_assignment | t2 | simple.test |

View File

@@ -1,7 +1,9 @@
| assignment.py:5 | a_0 | assignment.py:5 | Taint simple.test |
| assignment.py:6 | a_1 | assignment.py:6 | Taint simple.test |
| assignment.py:7 | b_1 | assignment.py:7 | Taint simple.test |
| assignment.py:13 | t1_0 | assignment.py:13 | Taint simple.test |
| assignment.py:13 | t2_0 | assignment.py:13 | Taint simple.test |
| assignment.py:14 | t1_1 | assignment.py:14 | Taint simple.test |
| carrier.py:4 | arg_0 | carrier.py:4 | Taint explicit.carrier |
| carrier.py:4 | arg_0 | carrier.py:4 | Taint simple.test |
| carrier.py:5 | self_1 | carrier.py:5 | Taint .attr = explicit.carrier |