fix(code-runtime-python): bind the send_done fallback primitives into locals and use a bare except

The done-frame fallback read _os_write/_memoryview/_FALLBACK_DONE_FRAME as module
globals at call time, so a single-line rebind of any of them reopened the
rebind hole the fallback exists to close. Bind them into _run locals before the
program runs, and use a bare except (which catches everything without naming
BaseException, so a rebind of that name cannot defeat the handler). The
transitive-name rebind test now also rebinds _os_write/_memoryview/
_FALLBACK_DONE_FRAME to pin the fallback's immunity.
This commit is contained in:
Chinesezjc
2026-08-31 14:33:31 +08:00
committed by Tianyi Cui
parent 31c3b425bf
commit 4ff050de71
2 changed files with 22 additions and 8 deletions
@@ -1488,7 +1488,8 @@ describe('PythonCodeRuntime — programs and bindings', () => {
// `__main__`, so rebinding `__main__._dump_scalar` to a raising function makes
// the error-frame encode throw AFTER the `except` block. `send_done` catches
// that and writes a fixed literal done frame (kind `exception`) with the
// captured `os.write`, so the host still gets a verdict — the run must be an
// LOCALLY-BOUND `_os_write`/`_memoryview`/`_FALLBACK_DONE_FRAME` captured
// before the program runs, so the host still gets a verdict — the run must be an
// `exception`, never a `worker-exit`. The real message is lost (the literal
// carries a fixed `<unrenderable>` text), which is acceptable: the verdict
// outranks the diagnostic detail.
@@ -1500,6 +1501,10 @@ describe('PythonCodeRuntime — programs and bindings', () => {
' raise RuntimeError("hijacked")',
'__main__._dump_scalar = boom',
'__main__.os = boom',
// The fallback must also survive a rebind of its own primitives.
'__main__._os_write = boom',
'__main__._memoryview = boom',
'__main__._FALLBACK_DONE_FRAME = boom',
'raise ValueError("real failure")',
].join('\n'),
bindings: [],