Skip to content

fix: SIGBUS on Apple Silicon — ObjC block PAC re-signing (v0.19.2)#90

Merged
kolkov merged 3 commits intomainfrom
fix/sigbus-objc-block-pac
Mar 1, 2026
Merged

fix: SIGBUS on Apple Silicon — ObjC block PAC re-signing (v0.19.2)#90
kolkov merged 3 commits intomainfrom
fix/sigbus-objc-block-pac

Conversation

@kolkov
Copy link
Contributor

@kolkov kolkov commented Mar 1, 2026

Summary

  • Fix SIGBUS crash on Apple Silicon caused by incorrect ObjC block ABI (_NSConcreteStackBlock on Go heap → PAC re-signing failure). Switch to _NSConcreteGlobalBlock + BLOCK_IS_GLOBAL flag, add blockPinRegistry for GC safety, remove stale runtime.KeepAlive(uintptr) no-ops.
  • CI: upgrade codecov-action v4 → v5, add codecov.yml
  • Tests: add coverage tests for core, HAL backends, format conversion

Fixes #89

Test plan

  • GOOS=darwin GOARCH=arm64 cross-compile clean
  • GOOS=darwin GOARCH=amd64 cross-compile clean
  • Windows tests pass (go test ./...)
  • Lint clean (golangci-lint run)
  • CI green
  • Real-device test by reporter (rcarlier, Apple M3) after release

kolkov added 3 commits March 1, 2026 17:59
- core/backend_test.go: backend registry, provider selection tests
- hal/backends_test.go: factory pattern, backend enumeration tests
- hal/dx12/convert_test.go: DX12 format/blend conversion tests
- hal/gles/convert_test.go: expanded GLES format conversion tests
- hal/noop/noop_test.go: expanded noop backend tests with error handling
- hal/software/software_test.go: expanded software backend tests
- hal/vulkan/convert_test.go: expanded Vulkan format conversion tests
…ocks

ObjC blocks were constructed with _NSConcreteStackBlock + flags=0, but
allocated on the Go heap. When Metal calls Block_copy() on these blocks
during addCompletedHandler:, ARM64e PAC re-signs the invoke pointer.
Our ffi.NewCallback pointers are unsigned, so authentication fails,
producing a corrupted pointer that causes SIGBUS when Metal's completion
queue invokes the callback.

Switch to _NSConcreteGlobalBlock + BLOCK_IS_GLOBAL (1<<28), which makes
Block_copy() a complete no-op (no memmove, no PAC re-signing). Add
blockPinRegistry (sync.Map) to keep block literals alive since global
blocks are not copied by Metal. Remove stale runtime.KeepAlive(uintptr)
calls that were no-ops (GC doesn't track uintptr as roots).

Fixes #89
@codecov
Copy link

codecov bot commented Mar 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@kolkov kolkov merged commit 49ef7bf into main Mar 1, 2026
11 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.

fix: SIGBUS on Apple Silicon — ObjC block uses _NSConcreteStackBlock incorrectly

1 participant