Skip to content

fix: WASM crash in cloudsync_set_column on tables with existing rows#42

Merged
andinux merged 2 commits intomainfrom
fix/wasm-block-allocator-signature
Apr 16, 2026
Merged

fix: WASM crash in cloudsync_set_column on tables with existing rows#42
andinux merged 2 commits intomainfrom
fix/wasm-block-allocator-signature

Conversation

@andinux
Copy link
Copy Markdown
Collaborator

@andinux andinux commented Apr 16, 2026

Summary

Calling cloudsync_set_column(table, col, 'algo', 'block') on a table with pre-existing rows crashes the WASM build with RuntimeError: function signature mismatch as soon as the block-index
migration tries to allocate memory. Native builds are unaffected.

Root cause

src/block.c:137 cast cloudsync_memory_alloc directly into the fractional-indexing allocator slot:

.malloc = (void ()(size_t))cloudsync_memory_alloc,

  • cloudsync_memory_alloc → dbmem_alloc(uint64_t)
  • fractional_indexing_allocator.malloc is void ()(size_t)

On native platforms size_t is 64-bit, so the cast is a no-op. In WASM size_t is 32-bit, and call_indirect enforces strict type checking: the function is registered in the table as (i64) -> i32 but
called as (i32) -> i32 — immediate runtime error. Documented Emscripten pitfall: https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html

Fix

Bridge through a thin fi_malloc_wrapper, mirroring the existing fi_calloc_wrapper pattern already used for the calloc slot. free is already fine (dbmem_free(void*) matches the expected signature
on every target).

Changes

  • src/block.c — new fi_malloc_wrapper, used in block_init_allocator
  • src/cloudsync.h — CLOUDSYNC_VERSION → 1.0.16
  • CHANGELOG.md — 1.0.16 entry

Test plan

  • make clean && make && make unittest — all tests pass (Block LWW suite + Memory Leaks Check)
  • make postgres-docker-run-test — 0 failures
  • Verify in a WASM build: cloudsync_set_column on a table with existing rows no longer raises function signature mismatch
  • Smoke-test block-level LWW roundtrip in the WASM environment

andinux added 2 commits April 16, 2026 14:13
cloudsync_memory_alloc (dbmem_alloc, uint64_t) was cast directly into
fractional_indexing_allocator.malloc (void *(*)(size_t)). Native size_t
is 64-bit so the cast is a no-op, but WASM size_t is 32-bit and
call_indirect enforces strict typing: the function is registered as
(i64)->i32 and called as (i32)->i32, crashing cloudsync_set_column on a
table with pre-existing rows during the block-index migration.

Bridge via fi_malloc_wrapper, matching the existing fi_calloc_wrapper
pattern.
@andinux andinux merged commit a24c691 into main Apr 16, 2026
27 checks passed
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.

1 participant