Memory corruption panic in async callbacks fix #16
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary: Fixed Memory Corruption Panic in Async Callbacks
The Bug
The library was misusing
cgo.Handlein every asynchronous function (e.g.,MapAsync,RequestAdapter,RequestDevice, and internal error scope checks).The code was creating a
cgo.Handleand then passing a pointer to that local variable (unsafe.Pointer(&handle)) to a C function. Since these functions are asynchronous, the Go function returns immediately and its stack frame is destroyed. When the C callback eventually fires, it attempts to dereference that now-invalid stack pointer to retrieve the handle, leading to:panic: runtime/cgo: misuse of an invalid HandleAffected Platforms
This issue likely affects all desktop platforms (macOS, Windows, Linux) where Go's CGO implementation is used. It was specifically observed and reproduced on macOS.
How to Reproduce
Buffer.MapAsync.runtime/cgopanic when a callback attempts to process an invalid pointer from a previous call's stack.The Fix
The fix implements the standard, safe pattern for passing
cgo.Handlethrough C:Pass by Value: Instead of passing the address of the handle variable, the handle (which is a
uintptrunder the hood) is converted directly to anunsafe.Pointerand passed as theuserdata.Cast on Recovery: In the Go callback exported to C, the
userdatais cast back to acgo.Handledirectly without dereferencing a pointer.This ensures that the handle value itself is preserved in the C
userdatafield, independent of the lifetime of the calling function's stack.