Skip to content

sdl: keep log output function on the Go side instead of passing a Go pointer to SDL - #627

Open
OvOhao wants to merge 1 commit into
veandco:masterfrom
OvOhao:fix-log-output-function
Open

OvOhao wants to merge 1 commit into
veandco:masterfrom
OvOhao:fix-log-output-function

Conversation

@OvOhao

@OvOhao OvOhao commented Oct 19, 2026

Copy link
Copy Markdown

Changes

LogSetOutputFunction gave SDL the address of a Go struct (logOutputFunctionCtx) as userdata. That caused two problems:

SDL has only one log output function at a time. So this change stores the callback and data in the existing logOutputFunctionCache / logOutputDataCache variables, guarded by a sync.RWMutex, and passes NULL as userdata. logOutputFunction reads the current values through LogGetOutputFunction. The unused logOutputFunctionCtx type is removed. log.c and the public API do not change.

The caches are set before SDL_LogSetOutputFunction is called, so the first message after registration already sees the new function. The lock is released before the user callback runs, so a callback can call LogSetOutputFunction or LogGetOutputFunction itself.

Testing

In Docker (golang:1.27, Debian libsdl2-dev 2.32.4):

  • go build ./sdl succeeds before and after. go vet ./sdl reports nothing in log.go. The existing vet findings in other files are unchanged.
  • go test -run 'TestLog' -v ./sdl: TestLog and TestLogSetOutputFunction pass before and after. The same tests also pass with -race after the change.
  • I also ran a temporary test (not included in this PR). It registers a closure that captures a variable and passes &struct{...} as data, runs runtime.GC() a few times, and then calls Log. Before: panic: runtime error: argument of cgo function has Go pointer to unpinned Go pointer at the LogSetOutputFunction call. After: the callback runs and receives the data.

Fixes #624
Fixes #626

…pointer to SDL

LogSetOutputFunction passed the address of a Go struct holding the
callback and its data to SDL_LogSetOutputFunction as userdata. Nothing
on the Go side kept that struct alive, so it could be collected while
SDL still used it, and cgo panics when the struct contains Go pointers
(capturing closures, method values, pointer data).

Store the callback and data in the existing package variables, guarded
by a mutex, and let logOutputFunction read them from there. SDL now gets
NULL as userdata.

Fixes veandco#624
Fixes veandco#626
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant