Skip to content

Commit d6d5937

Browse files
committed
Python: Fix flow through deepcopy
Or, more generally, any copy step, as these presumably do not preserve object identity. (Arguably, `copy` could still be susceptible to interior mutability, but I think that's outside the scope of this query anyway.)
1 parent 14c958a commit d6d5937

File tree

3 files changed

+6
-30
lines changed

3 files changed

+6
-30
lines changed

python/ql/src/semmle/python/functions/ModificationOfParameterWithDefault.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
private import python
1010
import semmle.python.dataflow.new.DataFlow
11+
private import semmle.python.dataflow.new.internal.TaintTrackingPrivate as TTP
1112

1213
/**
1314
* Provides a data-flow configuration for detecting modifications of a parameters default value.
@@ -69,6 +70,10 @@ module ModificationOfParameterWithDefault {
6970
// if we are tracking a empty default, then it is ok to modify non-empty values,
7071
// so our tracking ends at those.
7172
state = false and node instanceof MustBeNonEmpty
73+
or
74+
// the target of a copy step is (presumably) a different object, and hence modifications of
75+
// this object no longer matter for the purposes of this query.
76+
TTP::copyStep(_, node) and state in [true, false]
7277
}
7378
}
7479

python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/ModificationOfParameterWithDefault.expected

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
11
edges
2-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:128:14:128:14 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:34:149:34 | ControlFlowNode for x |
3-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:128:14:128:14 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:170:21:170:21 | ControlFlowNode for y |
4-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:13:149:13 | ControlFlowNode for y | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:178:12:178:12 | ControlFlowNode for y |
5-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:17:149:41 | ControlFlowNode for _deepcopy_atomic() | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:13:149:13 | ControlFlowNode for y |
6-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:34:149:34 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:17:149:41 | ControlFlowNode for _deepcopy_atomic() |
7-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:34:149:34 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:182:22:182:22 | ControlFlowNode for x |
8-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:170:21:170:21 | ControlFlowNode for y | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:178:12:178:12 | ControlFlowNode for y |
9-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:182:22:182:22 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:183:12:183:12 | ControlFlowNode for x |
102
| test.py:2:12:2:12 | ControlFlowNode for l | test.py:3:5:3:5 | ControlFlowNode for l |
113
| test.py:7:11:7:11 | ControlFlowNode for l | test.py:8:5:8:5 | ControlFlowNode for l |
124
| test.py:12:14:12:14 | ControlFlowNode for l | test.py:13:9:13:9 | ControlFlowNode for l |
@@ -48,20 +40,7 @@ edges
4840
| test.py:195:28:195:28 | ControlFlowNode for x | test.py:181:28:181:28 | ControlFlowNode for x |
4941
| test.py:197:18:197:18 | ControlFlowNode for x | test.py:198:28:198:28 | ControlFlowNode for x |
5042
| test.py:198:28:198:28 | ControlFlowNode for x | test.py:181:28:181:28 | ControlFlowNode for x |
51-
| test.py:216:30:216:30 | ControlFlowNode for x | test.py:217:18:217:18 | ControlFlowNode for x |
52-
| test.py:217:5:217:5 | ControlFlowNode for y | test.py:218:5:218:5 | ControlFlowNode for y |
53-
| test.py:217:9:217:19 | ControlFlowNode for deepcopy() | test.py:217:5:217:5 | ControlFlowNode for y |
54-
| test.py:217:18:217:18 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:128:14:128:14 | ControlFlowNode for x |
55-
| test.py:217:18:217:18 | ControlFlowNode for x | test.py:217:9:217:19 | ControlFlowNode for deepcopy() |
5643
nodes
57-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:128:14:128:14 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
58-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:13:149:13 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
59-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:17:149:41 | ControlFlowNode for _deepcopy_atomic() | semmle.label | ControlFlowNode for _deepcopy_atomic() |
60-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:34:149:34 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
61-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:170:21:170:21 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
62-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:178:12:178:12 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
63-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:182:22:182:22 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
64-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:183:12:183:12 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
6544
| test.py:2:12:2:12 | ControlFlowNode for l | semmle.label | ControlFlowNode for l |
6645
| test.py:3:5:3:5 | ControlFlowNode for l | semmle.label | ControlFlowNode for l |
6746
| test.py:7:11:7:11 | ControlFlowNode for l | semmle.label | ControlFlowNode for l |
@@ -128,14 +107,7 @@ nodes
128107
| test.py:195:28:195:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
129108
| test.py:197:18:197:18 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
130109
| test.py:198:28:198:28 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
131-
| test.py:216:30:216:30 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
132-
| test.py:217:5:217:5 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
133-
| test.py:217:9:217:19 | ControlFlowNode for deepcopy() | semmle.label | ControlFlowNode for deepcopy() |
134-
| test.py:217:18:217:18 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
135-
| test.py:218:5:218:5 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
136110
subpaths
137-
| file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:34:149:34 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:182:22:182:22 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:183:12:183:12 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:149:17:149:41 | ControlFlowNode for _deepcopy_atomic() |
138-
| test.py:217:18:217:18 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:128:14:128:14 | ControlFlowNode for x | file:///usr/local/python/3.10.13/lib/python3.10/copy.py:178:12:178:12 | ControlFlowNode for y | test.py:217:9:217:19 | ControlFlowNode for deepcopy() |
139111
#select
140112
| test.py:3:5:3:5 | ControlFlowNode for l | test.py:2:12:2:12 | ControlFlowNode for l | test.py:3:5:3:5 | ControlFlowNode for l | This expression mutates a $@. | test.py:2:12:2:12 | ControlFlowNode for l | default value |
141113
| test.py:8:5:8:5 | ControlFlowNode for l | test.py:7:11:7:11 | ControlFlowNode for l | test.py:8:5:8:5 | ControlFlowNode for l | This expression mutates a $@. | test.py:7:11:7:11 | ControlFlowNode for l | default value |
@@ -166,4 +138,3 @@ subpaths
166138
| test.py:185:9:185:9 | ControlFlowNode for x | test.py:197:18:197:18 | ControlFlowNode for x | test.py:185:9:185:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:197:18:197:18 | ControlFlowNode for x | default value |
167139
| test.py:187:9:187:9 | ControlFlowNode for x | test.py:194:18:194:18 | ControlFlowNode for x | test.py:187:9:187:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:194:18:194:18 | ControlFlowNode for x | default value |
168140
| test.py:187:9:187:9 | ControlFlowNode for x | test.py:197:18:197:18 | ControlFlowNode for x | test.py:187:9:187:9 | ControlFlowNode for x | This expression mutates a $@. | test.py:197:18:197:18 | ControlFlowNode for x | default value |
169-
| test.py:218:5:218:5 | ControlFlowNode for y | test.py:216:30:216:30 | ControlFlowNode for x | test.py:218:5:218:5 | ControlFlowNode for y | This expression mutates a $@. | test.py:216:30:216:30 | ControlFlowNode for x | default value |

python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,4 +215,4 @@ def flow_from_within_deepcopy_fp():
215215

216216
def flow_through_deepcopy_fp(x=[]):
217217
y = deepcopy(x)
218-
y.append(1) #$ SPURIOUS: modification=y
218+
y.append(1)

0 commit comments

Comments
 (0)