Skip to content

Commit 47c2c9e

Browse files
committed
Add test for FP for py/modification-of-locals
1 parent ea7510b commit 47c2c9e

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

python/ql/test/query-tests/Statements/general/ModificationOfLocals.expected

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,10 @@
33
| test.py:101:5:101:14 | Attribute() | Modification of the locals() dictionary will have no effect on the local variables. |
44
| test.py:102:9:102:14 | Subscript | Modification of the locals() dictionary will have no effect on the local variables. |
55
| test.py:103:5:103:13 | Attribute() | Modification of the locals() dictionary will have no effect on the local variables. |
6+
| test.py:206:5:206:11 | Subscript | Modification of the locals() dictionary will have no effect on the local variables. |
7+
| test.py:207:5:207:23 | Attribute() | Modification of the locals() dictionary will have no effect on the local variables. |
8+
| test.py:208:5:208:15 | Attribute() | Modification of the locals() dictionary will have no effect on the local variables. |
9+
| test.py:209:9:209:15 | Subscript | Modification of the locals() dictionary will have no effect on the local variables. |
10+
| test.py:210:5:210:14 | Attribute() | Modification of the locals() dictionary will have no effect on the local variables. |
11+
| test.py:228:9:228:24 | Subscript | Modification of the locals() dictionary will have no effect on the local variables. |
12+
| test.py:229:9:229:35 | Attribute() | Modification of the locals() dictionary will have no effect on the local variables. |

python/ql/test/query-tests/Statements/general/test.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,41 @@ class false_positive:
196196
class MyClass:
197197
locals()['x'] = 43 # OK
198198
y = x
199+
200+
201+
# Once a `locals()` dictionary is passed out of the scope that created it, it is
202+
# just an ordinary mapping. Modifying it in a different scope is meaningful and
203+
# effective, so these modifications must NOT be flagged: the "no effect on local
204+
# variables" gotcha only applies within the scope that called `locals()`.
205+
def modify_passed_dict(ns):
206+
ns['k'] = 1 # OK: `ns` is a parameter here, not this scope's locals()
207+
ns.update({'j': 2}) # OK
208+
ns.pop('k') # OK
209+
del ns['j'] # OK
210+
ns.clear() # OK
211+
212+
213+
def pass_locals_to_function():
214+
y = 1
215+
modify_passed_dict(locals())
216+
return y
217+
218+
219+
# The same situation, but where the `locals()` dictionary is laundered through an
220+
# instance attribute (as instance-attribute type tracking now models). These must
221+
# also not be flagged.
222+
class NamespaceHolder(object):
223+
224+
def __init__(self, ns):
225+
self.ns = ns
226+
227+
def populate(self):
228+
self.ns['extra'] = 1 # OK: different scope from the `locals()` call
229+
self.ns.update({'more': 2}) # OK
230+
231+
232+
def launder_locals_through_instance():
233+
x = 1
234+
holder = NamespaceHolder(locals())
235+
holder.populate()
236+
return x

0 commit comments

Comments
 (0)