Skip to content

Commit b11ba39

Browse files
nludbandpgeorge
authored andcommitted
rp2/modules: Fix memory leak and logic bug in handling of _pio_funcs.
The `rp2` package use a global dict `_pio_funcs` to populate a namespace for `@asm_pio` functions to be executed in. That dict is not cleaned up after use, keeping references to bound methods of a `PIOASMEmit`. By not setting/clearing all the functions, `asm_pio_encode` unintentionally allows the use of the old directives (harmless) as well as `jmp` (in general, produces the wrong output). Fix that by making sure `_pio_funcs` is returned to its original state after using it: - For `@asm_pio` update the target dict from `_pio_funcs` and then set additional functions as needed, leaving `_pio_funcs` unchanged. - For `asm_pio_encode`, borrow `_pio_funcs` to use as globals (avoiding a bunch of memory alloc/free) but delete the instruction entries after use. Signed-off-by: Neil Ludban <[email protected]>
1 parent 11c9656 commit b11ba39

File tree

1 file changed

+42
-49
lines changed

1 file changed

+42
-49
lines changed

ports/rp2/modules/rp2.py

Lines changed: 42 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -215,58 +215,55 @@ def set(self, dest, data):
215215
# "block": see above
216216
"clear": 0x40,
217217
"rel": lambda x: x | 0x10,
218-
# functions
219-
"wrap_target": None,
220-
"wrap": None,
221-
"label": None,
222-
"word": None,
223-
"nop": None,
224-
"jmp": None,
225-
"wait": None,
226-
"in_": None,
227-
"out": None,
228-
"push": None,
229-
"pull": None,
230-
"mov": None,
231-
"irq": None,
232-
"set": None,
233218
}
234219

235220

221+
_pio_directives = (
222+
"wrap_target",
223+
"wrap",
224+
"label",
225+
)
226+
227+
228+
_pio_instructions = (
229+
"word",
230+
"nop",
231+
"jmp",
232+
"wait",
233+
"in_",
234+
"out",
235+
"push",
236+
"pull",
237+
"mov",
238+
"irq",
239+
"set",
240+
)
241+
242+
236243
def asm_pio(**kw):
237244
emit = PIOASMEmit(**kw)
238245

239246
def dec(f):
240247
nonlocal emit
241248

242-
gl = _pio_funcs
243-
gl["wrap_target"] = emit.wrap_target
244-
gl["wrap"] = emit.wrap
245-
gl["label"] = emit.label
246-
gl["word"] = emit.word
247-
gl["nop"] = emit.nop
248-
gl["jmp"] = emit.jmp
249-
gl["wait"] = emit.wait
250-
gl["in_"] = emit.in_
251-
gl["out"] = emit.out
252-
gl["push"] = emit.push
253-
gl["pull"] = emit.pull
254-
gl["mov"] = emit.mov
255-
gl["irq"] = emit.irq
256-
gl["set"] = emit.set
257-
258-
old_gl = f.__globals__.copy()
259-
f.__globals__.clear()
260-
f.__globals__.update(gl)
249+
gl = f.__globals__
250+
old_gl = gl.copy()
251+
gl.clear()
252+
253+
gl.update(_pio_funcs)
254+
for name in _pio_directives:
255+
gl[name] = getattr(emit, name)
256+
for name in _pio_instructions:
257+
gl[name] = getattr(emit, name)
261258

262259
emit.start_pass(0)
263260
f()
264261

265262
emit.start_pass(1)
266263
f()
267264

268-
f.__globals__.clear()
269-
f.__globals__.update(old_gl)
265+
gl.clear()
266+
gl.update(old_gl)
270267

271268
return emit.prog
272269

@@ -284,19 +281,15 @@ def asm_pio_encode(instr, sideset_count, sideset_opt=False):
284281
emit.num_sideset = 0
285282

286283
gl = _pio_funcs
287-
gl["word"] = emit.word
288-
gl["nop"] = emit.nop
289-
# gl["jmp"] = emit.jmp currently not supported
290-
gl["wait"] = emit.wait
291-
gl["in_"] = emit.in_
292-
gl["out"] = emit.out
293-
gl["push"] = emit.push
294-
gl["pull"] = emit.pull
295-
gl["mov"] = emit.mov
296-
gl["irq"] = emit.irq
297-
gl["set"] = emit.set
298-
299-
exec(instr, gl)
284+
for name in _pio_instructions:
285+
gl[name] = getattr(emit, name)
286+
gl["jmp"] = None # emit.jmp currently not supported
287+
288+
try:
289+
exec(instr, gl)
290+
finally:
291+
for name in _pio_instructions:
292+
del gl[name]
300293

301294
if len(emit.prog[_PROG_DATA]) != 1:
302295
raise PIOASMError("expecting exactly 1 instruction")

0 commit comments

Comments
 (0)