tinygo icon indicating copy to clipboard operation
tinygo copied to clipboard

runtime: temporarily store waspi2 memory allocations from cabi_realloc

Open ydnar opened this issue 6 months ago • 3 comments

This is an initial take at solving the interaction between the TinyGo GC and the Component Model allocation scheme (cabi_realloc).

Specifically, when the host calls an exported function with argument(s) that require allocations, these are first allocated in the guest via calls to cabi_realloc, then these pointer(s) are passed to the function exported with go:wasmexport.

Because these allocated pointers are not stored anywhere in the TinyGo stack or heap, they are subject to immediate collection. This can happen if the host wants to copy a large string into the guest memory, and performs a sequence of cabi_realloc calls to grow the target memory.

The fix is simple: hold onto the pointers allocated by cabi_realloc until the next wasmexport function returns.

This logic currently works for reactor modules, where allocations created with cabi_realloc are held in memory until a go:wasmexport function exits. Caveat: when used with a long-running program like the default wasi-cli world, any allocations created via cabi_realloc will be held forever until func main exits.

This is intended to fix the problem in https://github.com/bytecodealliance/go-modules/issues/348.

ydnar avatar May 17 '25 23:05 ydnar

I think I have run into a similar problem using wasm-unknown and wasip1 having to do with lifetimes and memory. This PR makes me think about some ways to possibly look into it further for those targets.

In any case, this seems fine to me if it does fix the wasip2 issue as described.

@dgryski any comment here?

deadprogram avatar May 18 '25 10:05 deadprogram

I ran into a related issue with the wasmimport functions today and have a reproducer.

Unfortunately the fix in this PR will not fix that issue, and instead result in a memory leak.

Do not merge this.

ydnar avatar May 18 '25 17:05 ydnar

Because these allocated pointers are not stored anywhere in the TinyGo stack or heap, they are subject to immediate collection. This can happen if the host wants to copy a large string into the guest memory, and performs a sequence of cabi_realloc calls to grow the target memory.

We have the same issue for libc malloc/realloc. A simple solution would be to call libc_realloc instead (defined in arch_tinygwasm_malloc.go). That would also avoid duplicating this logic.

(I also see that libc_realloc has a bug in the precise GC: it allocates using make([]byte, ...) which tells the GC the buffer doesn't contain pointers but that is of course an incorrect assumption with C calloc).

EDIT: See: https://github.com/tinygo-org/tinygo/pull/4898

aykevl avatar May 21 '25 10:05 aykevl