Skip to content

fix: restore WASM stack in Database.exec to prevent stack leak (#630) - #631

Merged
lovasoa merged 1 commit into
masterfrom
fix/exec-stack-leak
Aug 14, 2026
Merged

fix: restore WASM stack in Database.exec to prevent stack leak (#630)#631
lovasoa merged 1 commit into
masterfrom
fix/exec-stack-leak

Conversation

@lovasoa

@lovasoa lovasoa commented Aug 14, 2026

Copy link
Copy Markdown
Member

Fixes #630

Problem

Database.prototype.exec calls stackAlloc(4) for pzTail but never pairs the allocation with stackSave()/stackRestore(). Every exec() call permanently consumes 16 bytes of the WASM stack, whether it succeeds or throws.

This is a regression from #606 (ee67aeb): that PR moved the SQL string from the stack to the heap (stringToNewUTF8) and correctly removed the surrounding stackSave()/stackRestore(), but left pzTail = stackAlloc(4) in place without cleanup. StatementIterator.next() does the same pzTail allocation but properly restores the stack in a finally block.

With the 5MB stack this exhausts after ~327k exec() calls (~16 bytes each), after which the module is corrupted (export/run/new Database all fail with unrelated errors) and the process can only be recovered by restarting. Long-lived processes using exec() as their normal query path hit this deterministically.

Fix

Restore the stack save/restore around exec():

var stack = stackSave();
// ...
} finally {
    if (originalSqlPtr) _free(originalSqlPtr);
    stackRestore(stack);
}

This keeps #606's desirable heap-allocation of the SQL string while freeing only the small per-call pzTail temporary.

Test

Added test/test_issue630.js which asserts SQL.stackSave() is unchanged after 1000 successful exec() calls and 100 failing ones. Verified the test fails without the fix (leak of 16000 after 1000 calls) and passes with it.

All 24 tests pass on wasm, wasm-debug, asm, and lint is clean.

exec() allocates pzTail with stackAlloc(4) but never pairs it with
stackSave()/stackRestore(), permanently consuming 16 bytes of the WASM
stack per call (success or failure). PR #606 removed the stack
save/restore when moving the SQL string to the heap but left the
pzTail allocation in place. With the 5MB stack this exhausts the
module after ~327k exec() calls, after which the module is corrupted.

Fixes #630
@lovasoa
lovasoa merged commit 5489808 into master Aug 14, 2026
2 checks passed
@lovasoa
lovasoa deleted the fix/exec-stack-leak branch August 14, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Database.exec() leaks 16 bytes of WASM stack per call — long-running apps eventually fail with "memory access out of bounds"

1 participant