From d9ed44d62c96ec86699dc73ef632cc2ccccb124e Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Thu, 27 Aug 2026 06:18:15 +0800 Subject: [PATCH] fix(code-runtime-python): skip zero-content open continuations in the hold; correct the spawn comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The review's items: a zero-content open continuation bills 0 but still pushed '' into the held fragment array, so a forged empty-open flood grew host memory without touching the ledger — the push is now skipped (an empty fragment contributes nothing to the merged entry). The spawn-site comment said a PATH change between load and run would fail with ENOENT; it actually makes spawn throw synchronously, which the surrounding try settles as worker-exit. --- .../code-runtime/code-runtime-python/src/index.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/code-runtime/code-runtime-python/src/index.ts b/packages/code-runtime/code-runtime-python/src/index.ts index 63c69291a1..ce572faaa9 100644 --- a/packages/code-runtime/code-runtime-python/src/index.ts +++ b/packages/code-runtime/code-runtime-python/src/index.ts @@ -1008,8 +1008,9 @@ export class PythonCodeRuntime extends CodeRuntime { // unaffected (it is a Python object, not the C-level stdio buffer). // Load validated that a basename resolves; absolute paths pass through. // The non-null assertion is the load-time contract (see the pythonBin - // load checks); PATH changing between load and run would fail the spawn - // with ENOENT, which the boot-write failure path settles as worker-exit. + // load checks); a PATH change between load and run would make this + // undefined and spawn throws synchronously, which the surrounding try + // settles as worker-exit like any other spawn failure. const resolvedPythonBin = resolvePythonBin(this.config.pythonBin) as string child = spawn(resolvedPythonBin, ['-u', '-I', bootstrapPath], { env: {}, @@ -1566,7 +1567,11 @@ export class PythonCodeRuntime extends CodeRuntime { } else { const bill = openParts.length === 0 ? cost + 1 : Math.max(cost - 2, 0) logBudget -= bill - openParts.push(message.text) + // A zero-content continuation (text '') bills 0; holding it + // would grow the fragment array without touching the ledger, + // so a forged empty-open flood could grow host memory — skip + // the push, the merge result is unchanged. + if (message.text !== '') openParts.push(message.text) } } return