From b5483c88592da3ccce7d1932cd33af12c78a4372 Mon Sep 17 00:00:00 2001 From: Andrea Donetti Date: Thu, 16 Apr 2026 14:13:08 -0600 Subject: [PATCH 1/2] fix: WASM signature mismatch in block fractional-indexing allocator 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. --- src/block.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/block.c b/src/block.c index ce252b4..dd99b26 100644 --- a/src/block.c +++ b/src/block.c @@ -127,6 +127,12 @@ block_list_t *block_split(const char *text, const char *delimiter) { // MARK: - Fractional indexing (via fractional-indexing submodule) - +// Wrapper for malloc: fractional_indexing expects size_t (32-bit on WASM) but cloudsync_memory_alloc takes uint64_t. +// A direct cast passes strict call_indirect type checking in WASM and triggers a RuntimeError. +static void *fi_malloc_wrapper(size_t size) { + return cloudsync_memory_alloc((uint64_t)size); +} + // Wrapper for calloc: fractional_indexing expects (count, size) but cloudsync_memory_zeroalloc takes a single size. static void *fi_calloc_wrapper(size_t count, size_t size) { return cloudsync_memory_zeroalloc((uint64_t)(count * size)); @@ -134,7 +140,7 @@ static void *fi_calloc_wrapper(size_t count, size_t size) { void block_init_allocator(void) { fractional_indexing_allocator alloc = { - .malloc = (void *(*)(size_t))cloudsync_memory_alloc, + .malloc = fi_malloc_wrapper, .calloc = fi_calloc_wrapper, .free = cloudsync_memory_free }; From 0f694ae1353bcd7fab7a07372c3c4e5f9d43dc7c Mon Sep 17 00:00:00 2001 From: Andrea Donetti Date: Thu, 16 Apr 2026 14:13:28 -0600 Subject: [PATCH 2/2] chore: bump version to 1.0.16 and update changelog --- CHANGELOG.md | 6 ++++++ src/cloudsync.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b462a84..b96bc16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [1.0.16] - 2026-04-16 + +### Fixed + +- **WASM crash in `cloudsync_set_column` on existing rows**: Calling `cloudsync_set_column(table, col, 'lww', 'block')` on a table with pre-existing rows crashed the WASM build with a `RuntimeError: function signature mismatch` as soon as the block-index migration tried to allocate memory. `block_init_allocator` was casting `cloudsync_memory_alloc` (a `uint64_t size` function) directly to the fractional-indexing allocator's `void *(*)(size_t)` slot. The cast is a no-op on native platforms where `size_t` is 64-bit, but WASM's `call_indirect` enforces strict type checking — the function is registered as `(i64) -> i32` and called as `(i32) -> i32`, triggering an immediate runtime error. A thin `fi_malloc_wrapper` (mirroring the existing `fi_calloc_wrapper`) now bridges the signatures. Native builds are unaffected. + ## [1.0.15] - 2026-04-16 ### Fixed diff --git a/src/cloudsync.h b/src/cloudsync.h index 0d86886..1bf0b53 100644 --- a/src/cloudsync.h +++ b/src/cloudsync.h @@ -18,7 +18,7 @@ extern "C" { #endif -#define CLOUDSYNC_VERSION "1.0.15" +#define CLOUDSYNC_VERSION "1.0.16" #define CLOUDSYNC_MAX_TABLENAME_LEN 512 #define CLOUDSYNC_VALUE_NOTSET -1