@@ -135,11 +135,6 @@ module EssaFlow {
135135 nodeTo = TIterableSequence ( target )
136136 )
137137 or
138- exists ( Assign assign , SequenceNode target | target .getNode ( ) = assign .getATarget ( ) |
139- nodeFrom .asExpr ( ) = assign .getValue ( ) and
140- nodeTo .asCfgNode ( ) = target
141- )
142- or
143138 // With definition
144139 // `with f(42) as x:`
145140 // nodeFrom is `f(42)`, cfg node
@@ -153,6 +148,10 @@ module EssaFlow {
153148 contextManager .strictlyDominates ( var )
154149 )
155150 or
151+ // Paramter definition
152+ // `def foo(x):`
153+ // nodeFrom is `x`, cfgNode
154+ // nodeTo is `x`, essa var
156155 exists ( ParameterDefinition pd |
157156 nodeFrom .asCfgNode ( ) = pd .getDefiningNode ( ) and
158157 nodeTo .asVar ( ) = pd .getVariable ( )
@@ -175,6 +174,7 @@ module EssaFlow {
175174 // If expressions
176175 nodeFrom .asCfgNode ( ) = nodeTo .asCfgNode ( ) .( IfExprNode ) .getAnOperand ( )
177176 or
177+ // Flow inside an unpacking assignment
178178 unpackingAssignmentFlowStep ( nodeFrom , nodeTo )
179179 or
180180 // Overflow keyword argument
@@ -1039,7 +1039,7 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
10391039 *
10401040 * We may for instance have
10411041 * ```python
1042- * (a, b) = ["a", "tainted string"] # RHS has content `ListElement `
1042+ * (a, b) = ["a", "tainted string"] # RHS has content `ListElementContent `
10431043 * ```
10441044 * Due to the abstraction for list content, we do not know whether `"tainted string"`
10451045 * ends up in `a` or in `b`, so we want to overapproximate and see it in both.
@@ -1054,14 +1054,14 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
10541054 *
10551055 * For a precise transfer
10561056 * ```python
1057- * (a, b) = ("a", "tainted string") # RHS has content `TupleElement (1)`
1057+ * (a, b) = ("a", "tainted string") # RHS has content `TupleElementContent (1)`
10581058 * ```
10591059 * we wish to keep the precision, so only `b` receives the tuple content at index 1.
10601060 *
10611061 * Finally, `sequence` is actually a pattern and can have a more complicated structure,
10621062 * such as
10631063 * ```python
1064- * (a, [b, *c]) = ("a", ("tainted string", "c")) # RHS has content `TupleElement (1); TupleElement (0)`
1064+ * (a, [b, *c]) = ("a", ("tainted string", "c")) # RHS has content `TupleElementContent (1); TupleElementContent (0)`
10651065 * ```
10661066 * where `a` should not receive content, but `b` and `c` should. `c` will be `["c"]` so
10671067 * should have the content converted and transferred, while `b` should read it.
@@ -1071,15 +1071,20 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
10711071 * For this we need a synthetic node in the middle, which we call `TIterableElement(receiver)`.
10721072 * It is associated with the receiver of the transfer, because we know the receiver type from the syntax.
10731073 * Since we sometimes need a converting read step (in the example above, `[b, *c]` reads the content
1074- * `TupleElement (0)` but should have content `ListElement `), we actually need a second synthetic node.
1074+ * `TupleElementContent (0)` but should have content `ListElementContent `), we actually need a second synthetic node.
10751075 * A converting read step is a read step followed by a converting transfer.
10761076 * We can have a uniform treatment by always having two synthetic nodes and so we can view it as
10771077 * two stages of the same node. So we read into (or transfer to) `TIterableSequence(receiver)`,
10781078 * from which we take a read step to `TIterableElement(receiver)` and then a store step to `receiver`.
10791079 * In order to preserve precise content, we also take a flow step from `TIterableSequence(receiver)`
10801080 * directly to `receiver`.
10811081 *
1082- * The strategy is then via several read-, store-, and flow steps:
1082+ * The strategy is then via several read-, store-, and flow steps, illustrated on the assignment
1083+ *
1084+ * ```python
1085+ * (a, [b, *c]) = ["a", [SOURCE]]
1086+ * ```
1087+ *
10831088 * 1. [Flow] Content is transferred from `iterable` to `TIterableSequence(sequence)` via a
10841089 * flow step. From here, everything happens on the LHS.
10851090 *
@@ -1094,17 +1099,61 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
10941099 * Here the content type is chosen according to the type of sequence.
10951100 *
10961101 * 5. [Read] Content is read from `sequence` to its elements according to the type of `sequence`.
1097- * If the element is a plain variable, the target is the corresponding essa node.
1098- * If the element is itelf a sequence, with control-flow node `seq`, the target is `TIterableSequence(seq)`.
1099- * If the element is a starred variable, with control-flow node `v`, the target is `TIterableElement(v)`.
1102+ * a) If the element is a plain variable, the target is the corresponding essa node.
1103+ *
1104+ * b) If the element is itelf a sequence, with control-flow node `seq`, the target is `TIterableSequence(seq)`.
1105+ *
1106+ * c) If the element is a starred variable, with control-flow node `v`, the target is `TIterableElement(v)`.
11001107 *
11011108 * 6. [Store] Content is stored from `TIterableElement(v)` to the essa variable for `v`, with
1102- * content type `ListElement`.
1109+ * content type `ListElementContent`.
1110+ * (We will see this in step 7)
1111+ *
1112+ * 7. [Flow, Read, Store] Steps 2 through 7 are repeated for all recursive elements which are sequences.
1113+ *
1114+ *
1115+ * We illustrate the above steps on the assignment
1116+ * ```python
1117+ * (a, [b, *c]) = ["a", [SOURCE]]
1118+ * ```
1119+ * where the path to `c` is
1120+ *
1121+ * `["a", [SOURCE]]`: [ListElementContent; ListElementContent]
1122+ *
1123+ * --Step 1-->
11031124 *
1104- * 7. [Flow, Read, Store] The last 5 steps are repeated for all recursive elements which are sequences.
1125+ * `TIterableSequence((a, [b, *c]))`: [ListElementContent; ListElementContent]
1126+ *
1127+ * --Step 3-->
1128+ *
1129+ * `TIterableElement((a, [b, *c]))`: [ListElementContent]
1130+ *
1131+ * --Step 4-->
1132+ *
1133+ * `(a, [b, *c])`: [TupleElementContent(1); ListElementContent]
1134+ *
1135+ * --Step 5b-->
1136+ *
1137+ * `TIterableSequence([b, *c])`: [ListElementContent]
1138+ *
1139+ * --Step 3-->
1140+ *
1141+ * `TIterableElement([b, *c])`: []
1142+ *
1143+ * --Step 4-->
1144+ *
1145+ * `[b, *c]`: [ListElementContent]
1146+ *
1147+ * --Step 5c-->
1148+ *
1149+ * `TIterableElement(c)`: []
1150+ *
1151+ * --Step 6-->
1152+ *
1153+ * `c`: [ListElementContent]
11051154 */
11061155module UnpackingAssignment {
1107- /** A direct (or top-level) target of an unpacking assignment */
1156+ /** A direct (or top-level) target of an unpacking assignment. */
11081157 class UnpackingAssignmentDirectTarget extends ControlFlowNode {
11091158 Expr value ;
11101159
@@ -1116,7 +1165,7 @@ module UnpackingAssignment {
11161165 Expr getValue ( ) { result = value }
11171166 }
11181167
1119- /** A (possibly recursive) target of an unpacking assignment */
1168+ /** A (possibly recursive) target of an unpacking assignment. */
11201169 class UnpackingAssignmentTarget extends ControlFlowNode {
11211170 UnpackingAssignmentTarget ( ) {
11221171 this instanceof UnpackingAssignmentDirectTarget
@@ -1129,15 +1178,22 @@ module UnpackingAssignment {
11291178 ControlFlowNode getAnElement ( ) { result = this .getElement ( _) }
11301179 }
11311180
1181+ /** A (possibly recursive) target of an unpacking assignment which is also a sequence. */
1182+ class UnpackingAssignmentSequenceTarget extends UnpackingAssignmentTarget {
1183+ UnpackingAssignmentSequenceTarget ( ) { this instanceof SequenceNode }
1184+ }
1185+
1186+ /** Step 2 */
11321187 predicate unpackingAssignmentFlowStep ( Node nodeFrom , Node nodeTo ) {
1133- exists ( UnpackingAssignmentTarget target | target instanceof SequenceNode |
1188+ exists ( UnpackingAssignmentSequenceTarget target |
11341189 nodeFrom = TIterableSequence ( target ) and
11351190 nodeTo .asCfgNode ( ) = target
11361191 )
11371192 }
11381193
1194+ /** Step 3 */
11391195 predicate unpackingAssignmentConvertingReadStep ( Node nodeFrom , Content c , Node nodeTo ) {
1140- exists ( UnpackingAssignmentTarget target | target instanceof SequenceNode |
1196+ exists ( UnpackingAssignmentSequenceTarget target |
11411197 nodeFrom = TIterableSequence ( target ) and
11421198 nodeTo = TIterableElement ( target ) and
11431199 (
@@ -1156,8 +1212,9 @@ module UnpackingAssignment {
11561212 )
11571213 }
11581214
1215+ /** Step 4 */
11591216 predicate unpackingAssignmentConvertingStoreStep ( Node nodeFrom , Content c , Node nodeTo ) {
1160- exists ( UnpackingAssignmentTarget target | target instanceof SequenceNode |
1217+ exists ( UnpackingAssignmentSequenceTarget target |
11611218 nodeFrom = TIterableElement ( target ) and
11621219 nodeTo .asCfgNode ( ) = target and
11631220 (
@@ -1172,6 +1229,7 @@ module UnpackingAssignment {
11721229 )
11731230 }
11741231
1232+ /** Step 5 */
11751233 predicate unpackingAssignmentElementReadStep ( Node nodeFrom , Content c , Node nodeTo ) {
11761234 exists ( UnpackingAssignmentTarget target , int index , ControlFlowNode element , boolean precise |
11771235 target instanceof SequenceNode
@@ -1190,21 +1248,25 @@ module UnpackingAssignment {
11901248 (
11911249 if element instanceof SequenceNode
11921250 then
1251+ // Step 5b
11931252 nodeTo = TIterableSequence ( element ) and
11941253 precise = true
11951254 else
11961255 if element .getNode ( ) instanceof Starred
11971256 then
1257+ // Step 5c
11981258 nodeTo = TIterableElement ( element ) and
11991259 precise = false
12001260 else (
1261+ // Step 5a
12011262 nodeTo .asVar ( ) .getDefinition ( ) .( MultiAssignmentDefinition ) .getDefiningNode ( ) = element and
12021263 precise = true
12031264 )
12041265 )
12051266 )
12061267 }
12071268
1269+ /** Step 6 */
12081270 predicate unpackingAssignmentStarredElementStoreStep ( Node nodeFrom , Content c , Node nodeTo ) {
12091271 exists ( ControlFlowNode starred | starred .getNode ( ) instanceof Starred |
12101272 nodeFrom = TIterableElement ( starred ) and
@@ -1213,13 +1275,14 @@ module UnpackingAssignment {
12131275 )
12141276 }
12151277
1216- /** Data flows from an iterable to an assigned variable . */
1278+ /** All read steps associated with unpacking assignment . */
12171279 predicate unpackingAssignmentReadStep ( Node nodeFrom , Content c , Node nodeTo ) {
12181280 unpackingAssignmentElementReadStep ( nodeFrom , c , nodeTo )
12191281 or
12201282 unpackingAssignmentConvertingReadStep ( nodeFrom , c , nodeTo )
12211283 }
12221284
1285+ /** All store steps associated with unpacking assignment. */
12231286 predicate unpackingAssignmentStoreStep ( Node nodeFrom , Content c , Node nodeTo ) {
12241287 unpackingAssignmentStarredElementStoreStep ( nodeFrom , c , nodeTo )
12251288 or
0 commit comments