fix: copy JSON string before dispatch_async in menu functions#192
Open
stefandevo wants to merge 1 commit intoblackboardsh:mainfrom
Open
fix: copy JSON string before dispatch_async in menu functions#192stefandevo wants to merge 1 commit intoblackboardsh:mainfrom
stefandevo wants to merge 1 commit intoblackboardsh:mainfrom
Conversation
The native setApplicationMenu, showContextMenu, and setTrayMenuFromJSON functions use dispatch_async to schedule work on the main thread, but capture the raw `const char *` pointer by value. By the time the main thread dequeues the block, Bun's GC has freed or overwritten the memory backing that pointer, resulting in: Failed to parse JSON: Unable to parse empty data. Fix: copy the C string into an NSString (owned by ObjC ARC) before the dispatch_async block, so the block captures an ARC-managed copy that remains valid regardless of Bun's GC timing. Fixes blackboardsh#160, blackboardsh#136, blackboardsh#191
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
const char *jsonStringinto anNSString(ARC-managed) beforedispatch_asyncin all three affected functions:setApplicationMenu,showContextMenu, andsetTrayMenuFromJSONNSStringcopy, which is retained by ARC regardless of Bun's GC timingProblem
The native Obj-C functions receive a
const char *from Bun's FFI and pass it into adispatch_async(dispatch_get_main_queue(), ...)block. The block captures the raw pointer by value. By the time the main thread dequeues and executes the block, Bun's garbage collector has freed or overwritten the memory at that address, resulting in:The menu bar shows only the app name with no subitems or additional menus.
Root cause
toCString()in the JS layer creates aBuffer.from(string)and returnsptr(buf). TheBufferis a local variable that becomes GC-eligible immediately after the FFI call returns. For synchronous native calls this is fine (the native code reads the string before returning), butdispatch_asyncdefers the read to a later main-thread tick — by which time the buffer is gone.A JS-side workaround (pinning the buffer to
globalThis) was attempted indist-macos-arm64but:dist/copy (which is whatpackage.jsonexports actually resolve to) was never patchedBuffer.from()may use Bun's pooled slab allocator, and subsequent buffer allocations can overwrite the slab regionFix
The proper fix is on the native side — one line per function:
Called before
dispatch_async, so the block captures an ARC-retainedNSStringinstead of a rawconst char *. TheNSDatais then created from the copy inside the block:Affected functions
setApplicationMenunativeWrapper.mmshowContextMenunativeWrapper.mmsetTrayMenuFromJSONnativeWrapper.mmTest plan
setApplicationMenuwith top-levelawaitin the entry pointFixes #160, #136, #191
🤖 Generated with Claude Code