@@ -712,32 +712,16 @@ private class EssaTaintTracking extends string {
712
712
TaintTrackingNode src , MultiAssignmentDefinition defn , TaintTrackingContext context ,
713
713
AttributePath path , TaintKind kind
714
714
) {
715
- exists ( DataFlow:: Node srcnode , TaintKind srckind , Assign assign |
715
+ exists ( DataFlow:: Node srcnode , TaintKind srckind , Assign assign , int depth |
716
716
src = TTaintTrackingNode_ ( srcnode , context , path , srckind , this ) and
717
717
path .noAttribute ( )
718
718
|
719
719
assign .getValue ( ) .getAFlowNode ( ) = srcnode .asCfgNode ( ) and
720
- kind = iterable_unpacking_descent ( assign .getATarget ( ) .getAFlowNode ( ) , defn .getDefiningNode ( ) ,
721
- srckind )
720
+ depth = iterable_unpacking_descent ( assign .getATarget ( ) .getAFlowNode ( ) , defn .getDefiningNode ( ) ) and
721
+ kind = taint_at_depth ( srckind , depth )
722
722
)
723
723
}
724
724
725
- /** `((x,y), ...) = value` with any nesting on LHS */
726
- private TaintKind iterable_unpacking_descent (
727
- SequenceNode left_parent , ControlFlowNode left_defn , CollectionKind parent_kind
728
- ) {
729
- //TODO: Fix the cartesian product in this predicate
730
- none ( ) and
731
- left_parent .getAnElement ( ) = left_defn and
732
- // Handle `a, *b = some_iterable`
733
- if left_defn instanceof StarredNode
734
- then result = parent_kind
735
- else result = parent_kind .getMember ( )
736
- or
737
- result = iterable_unpacking_descent ( left_parent .getAnElement ( ) , left_defn ,
738
- parent_kind .getMember ( ) )
739
- }
740
-
741
725
pragma [ noinline]
742
726
private predicate taintedAttributeAssignment (
743
727
TaintTrackingNode src , AttributeAssignment defn , TaintTrackingContext context ,
@@ -967,6 +951,45 @@ private predicate piNodeTestAndUse(PyEdgeRefinement defn, ControlFlowNode test,
967
951
test = defn .getTest ( ) and use = defn .getInput ( ) .getASourceUse ( ) and test .getAChild * ( ) = use
968
952
}
969
953
954
+ /** Helper predicate for taintedMultiAssignment */
955
+ private TaintKind taint_at_depth ( SequenceKind parent_kind , int depth ) {
956
+ depth >= 0 and
957
+ (
958
+ // base-case #0
959
+ depth = 0 and
960
+ result = parent_kind
961
+ or
962
+ // base-case #1
963
+ depth = 1 and
964
+ result = parent_kind .getMember ( )
965
+ or
966
+ // recursive case
967
+ result = taint_at_depth ( parent_kind .getMember ( ) , depth - 1 )
968
+ )
969
+ }
970
+
971
+ /** Helper predicate for taintedMultiAssignment
972
+ *
973
+ * Returns the `depth` the elements that are assigned to `left_defn` with iterable unpacking has,
974
+ * compared to `left_parent`. Special care is taken for `StarredNode` that is assigned a sequence of items.
975
+ *
976
+ * For example, `((x, *y), ...) = value` with any nesting on LHS
977
+ * - with `left_defn` = `x`, `left_parent` = `(x, *y)`, result = 1
978
+ * - with `left_defn` = `x`, `left_parent` = `((x, *y), ...)`, result = 2
979
+ * - with `left_defn` = `*y`, `left_parent` = `(x, *y)`, result = 0
980
+ * - with `left_defn` = `*y`, `left_parent` = `((x, *y), ...)`, result = 1
981
+ */
982
+ int iterable_unpacking_descent ( SequenceNode left_parent , ControlFlowNode left_defn ) {
983
+ exists ( Assign a | a .getATarget ( ) .getASubExpression * ( ) .getAFlowNode ( ) = left_parent ) and
984
+ left_parent .getAnElement ( ) = left_defn and
985
+ // Handle `a, *b = some_iterable`
986
+ if left_defn instanceof StarredNode
987
+ then result = 0
988
+ else result = 1
989
+ or
990
+ result = 1 + iterable_unpacking_descent ( left_parent .getAnElement ( ) , left_defn )
991
+ }
992
+
970
993
module Implementation {
971
994
/* A call that returns a copy (or similar) of the argument */
972
995
predicate copyCall ( ControlFlowNode fromnode , CallNode tonode ) {
0 commit comments