progrium/darwinkit

OpenGL app crashes

Closed this issue · 5 comments

I have a GTK app. I want to use macdriver to implement a native UI. The project is https://gitlab.com/eukano/runway. I'm executing go run ./cmd/runway view. It works for a few minutes or a few seconds, but it always crashes.

It occasionally fails in GC (in Go): gc1.log, gc2.log (GC error dumps are pretty long). Most of the time my app fails during an Objective-C call:

$ go run ./cmd/runway view
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x143545348 pc=0x7fff201aee89]

runtime stack:
runtime.throw(0x4c901c3, 0x2a)
        /GOROOTS/1.16.2/go/src/runtime/panic.go:1117 +0x72
runtime.sigpanic()
        /GOROOTS/1.16.2/go/src/runtime/signal_unix.go:718 +0x2ef

goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x4a50e10, 0xc0002fece8, 0x8)
        /GOROOTS/1.16.2/go/src/runtime/cgocall.go:154 +0x5b fp=0xc0002fecb8 sp=0xc0002fec80 pc=0x4006f7b
github.com/progrium/macdriver/objc._Cfunc_GoObjc_TypeInfoForMethod(0x143545348, 0x7fff7c628991, 0x0)
        _cgo_gotypes.go:263 +0x49 fp=0xc0002fece8 sp=0xc0002fecb8 pc=0x4a1bfe9
github.com/progrium/macdriver/objc.typeInfoForMethod.func1(0x5107518, 0xc00063e378, 0x7fff7c628991, 0xc00063e378)
        /PROJ/macdriver/objc/selector.go:85 +0x96 fp=0xc0002fed20 sp=0xc0002fece8 pc=0x4a25e56
github.com/progrium/macdriver/objc.typeInfoForMethod(0x5106da8, 0xc00063e370, 0x4c3da0c, 0xd, 0xc0002feda8, 0x4a1bd25)
        /PROJ/macdriver/objc/selector.go:85 +0x7d fp=0xc0002fed58 sp=0xc0002fed20 pc=0x4a24cdd
github.com/progrium/macdriver/objc.simpleTypeInfoForMethod(0x5106da8, 0xc00063e370, 0x4c3da0c, 0xd, 0xbff0000000000000, 0x0)
        /PROJ/macdriver/objc/selector.go:113 +0x59 fp=0xc0002fede0 sp=0xc0002fed58 pc=0x4a24d79
github.com/progrium/macdriver/objc.sendMsg(0x5106da8, 0xc00063e370, 0x4c3b11f, 0xc, 0x4c3da0c, 0xd, 0x0, 0x0, 0x0, 0x0, ...)
        /PROJ/macdriver/objc/msg_amd64.go:85 +0xe9 fp=0xc0002fefb8 sp=0xc0002fede0 pc=0x4a214a9
github.com/progrium/macdriver/objc.object.Send(...)
        /PROJ/macdriver/objc/msg_amd64.go:234
github.com/progrium/macdriver/objc.(*object).Send(0xc00063e338, 0x4c3da0c, 0xd, 0x0, 0x0, 0x0, 0x5106da8, 0x561ff00)
        <autogenerated>:1 +0xa8 fp=0xc0002ff020 sp=0xc0002fefb8 pc=0x4a28088
main.(*GLView).drawRect(0xc000caa018, 0x100000000000000)
        /PROJ/runway/cmd/runway/view_cocoa.go:172 +0x139 fp=0xc0002ff080 sp=0xc0002ff020 pc=0x4a47079
runtime.call16(0xc000ca6120, 0x4f8c5f0, 0xc000122930, 0x1000000010)
        /GOROOTS/1.16.2/go/src/runtime/asm_amd64.s:550 +0x3e fp=0xc0002ff0a0 sp=0xc0002ff080 pc=0x4078a1e
reflect.Value.call(0x4adf7a0, 0x4f8c5f0, 0x13, 0x4c2a426, 0x4, 0xc000ca6510, 0x2, 0x2, 0x2, 0x18, ...)
        /GOROOTS/1.16.2/go/src/reflect/value.go:476 +0x8e7 fp=0xc0002ff2a8 sp=0xc0002ff0a0 pc=0x40b9c67
reflect.Value.Call(0x4adf7a0, 0x4f8c5f0, 0x13, 0xc000ca6510, 0x2, 0x2, 0x1, 0x2, 0x0)
        /GOROOTS/1.16.2/go/src/reflect/value.go:337 +0xb9 fp=0xc0002ff328 sp=0xc0002ff2a8 pc=0x40b9139
github.com/progrium/macdriver/objc.goMethodCallEntryPoint(0x7ffeefbfc040, 0x40074fb)
        /PROJ/macdriver/objc/call_amd64.go:273 +0x27f0 fp=0xc0002ff7a8 sp=0xc0002ff328 pc=0x4a1edd0
_cgoexp_6ee9b331048c_goMethodCallEntryPoint(0x7ffeefbfc010)
        _cgo_gotypes.go:297 +0x2e fp=0xc0002ff7c8 sp=0xc0002ff7a8 pc=0x4a2604e
runtime.cgocallbackg1(0x4a26020, 0x7ffeefbfc010, 0x0)
        /GOROOTS/1.16.2/go/src/runtime/cgocall.go:292 +0x18c fp=0xc0002ff868 sp=0xc0002ff7c8 pc=0x400732c
runtime.cgocallbackg(0x4a26020, 0x7ffeefbfc010, 0x0)
        /GOROOTS/1.16.2/go/src/runtime/cgocall.go:228 +0xda fp=0xc0002ff8d8 sp=0xc0002ff868 pc=0x40070fa
runtime.cgocallback(0x4006f9f, 0x4a5f0b0, 0xc0002ff970)
        /GOROOTS/1.16.2/go/src/runtime/asm_amd64.s:788 +0xa9 fp=0xc0002ff900 sp=0xc0002ff8d8 pc=0x407a1e9
runtime.asmcgocall(0x4a5f0b0, 0xc0002ff970)
        /GOROOTS/1.16.2/go/src/runtime/asm_amd64.s:652 +0x42 fp=0xc0002ff908 sp=0xc0002ff900 pc=0x407a0c2
runtime.cgocall(0x4a5f0b0, 0xc0002ff970, 0xc0002ff980)
        /GOROOTS/1.16.2/go/src/runtime/cgocall.go:164 +0x7f fp=0xc0002ff940 sp=0xc0002ff908 pc=0x4006f9f
github.com/progrium/macdriver/misc/variadic._Cfunc_VariadicCall(0xc000150090, 0x0)
        _cgo_gotypes.go:73 +0x45 fp=0xc0002ff970 sp=0xc0002ff940 pc=0x4a1a565
github.com/progrium/macdriver/misc/variadic.(*FunctionCall).Call.func1(0xc000150090, 0xc0002ffa0c)
        /PROJ/macdriver/misc/variadic/variadic_amd64.go:68 +0x4d fp=0xc0002ff9a0 sp=0xc0002ff970 pc=0x4a1a9ad
github.com/progrium/macdriver/misc/variadic.(*FunctionCall).Call(0xc000150090, 0x76)
        /PROJ/macdriver/misc/variadic/variadic_amd64.go:68 +0x2b fp=0xc0002ff9c0 sp=0xc0002ff9a0 pc=0x4a1a86b
github.com/progrium/macdriver/objc.sendMsg(0x5106da8, 0xc00063e120, 0x4c3b11f, 0xc, 0x4c2a10e, 0x3, 0x0, 0x0, 0x0, 0x0, ...)
        /PROJ/macdriver/objc/msg_amd64.go:230 +0x705 fp=0xc0002ffb98 sp=0xc0002ff9c0 pc=0x4a21ac5
github.com/progrium/macdriver/objc.object.Send(...)
        /PROJ/macdriver/objc/msg_amd64.go:234
github.com/progrium/macdriver/objc.(*object).Send(0xc000389200, 0x4c2a10e, 0x3, 0x0, 0x0, 0x0, 0x5106da8, 0x561ff08)
        <autogenerated>:1 +0xa8 fp=0xc0002ffc00 sp=0xc0002ffb98 pc=0x4a28088
github.com/progrium/macdriver/cocoa.NSApplication.Run(...)
        /PROJ/macdriver/cocoa/NSApplication.go:51
main.viewRun(0x56a5340, 0x570c4e0, 0x0, 0x0)
        /PROJ/runway/cmd/runway/view_cocoa.go:128 +0x376 fp=0xc0002ffcc0 sp=0xc0002ffc00 pc=0x4a46936
github.com/spf13/cobra.(*Command).execute(0x56a5340, 0x570c4e0, 0x0, 0x0, 0x56a5340, 0x570c4e0)
        /GOROOTS/1.16.2/packages/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856 +0x2c2 fp=0xc0002ffd80 sp=0xc0002ffcc0 pc=0x42094e2
github.com/spf13/cobra.(*Command).ExecuteC(0x56a4940, 0x4c2d747, 0x6, 0x4c64d38)
        /GOROOTS/1.16.2/packages/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960 +0x375 fp=0xc0002ffe60 sp=0xc0002ffd80 pc=0x420a215
main.main()
        /PROJ/runway/cmd/runway/main.go:37 +0x21c fp=0xc0002fff88 sp=0xc0002ffe60 pc=0x4a4563c
runtime.main()
        /GOROOTS/1.16.2/go/src/runtime/proc.go:225 +0x256 fp=0xc0002fffe0 sp=0xc0002fff88 pc=0x4041536
runtime.goexit()
        /GOROOTS/1.16.2/go/src/runtime/asm_amd64.s:1371 +0x1 fp=0xc0002fffe8 sp=0xc0002fffe0 pc=0x407a461
exit status 2

Be sure to use runtime.LockOSThread() and use core.Dispatch where appropriate. There's a better version at https://github.com/progrium/shelldriver/tree/main/dispatch which should be added here soon.

With pthread_self and pthread_threadid_np, I've verified that all my UI code is running on the main thread. I lock the OS thread in init, and the period updates are handled via NSTimer. The stack trace below exploded on v.SendSuper("drawRect:", r) - it appears that SendSuper sent a message to the class, instead of the instance.

[Init] Thread 5136748
[Main] Thread 5136748
[DidLaunch] Thread 5136748
[Awake] Thread 5136748
[Draw] Thread 5136748
...
[Draw] Thread 5136748
2021-07-26 16:19:44.950 runway[28266:5136748] +[RWOpenGLView drawRect:]: unrecognized selector sent to class 0xb6040e0
2021-07-26 16:19:44.952 runway[28266:5136748] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[RWOpenGLView drawRect:]: unrecognized selector sent to class 0xb6040e0'
*** First throw call stack:
(
        0   CoreFoundation                      0x00007fff204836af __exceptionPreprocess + 242
        1   libobjc.A.dylib                     0x00007fff201bb3c9 objc_exception_throw + 48
        2   CoreFoundation                      0x00007fff20505bdd __CFExceptionProem + 0
        3   CoreFoundation                      0x00007fff203eb07d ___forwarding___ + 1467
        4   CoreFoundation                      0x00007fff203eaa38 _CF_forwarding_prep_0 + 120
        5   runway                              0x0000000004a5c18b memdone + 14
        6   runway                              0x0000000004a5c06d _cgo_a79dd45daf7f_Cfunc_VariadicCall + 29
        7   runway                              0x0000000004078610 runtime.asmcgocall + 112
)
libc++abi.dylib: terminating with uncaught exception of type NSException
SIGABRT: abort
PC=0x7fff202e3462 m=0 sigcode=0
signal arrived during cgo execution

goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x4a5c050, 0xc000374d90, 0x56d8220)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/runtime/cgocall.go:154 +0x5b fp=0xc000374d60 sp=0xc000374d28 pc=0x400549b
github.com/progrium/macdriver/misc/variadic._Cfunc_VariadicCall(0xc0001c6ea0, 0x0)
        _cgo_gotypes.go:73 +0x45 fp=0xc000374d90 sp=0xc000374d60 pc=0x4a18a85
github.com/progrium/macdriver/misc/variadic.(*FunctionCall).Call.func1(0xc0001c6ea0, 0xc000198a00)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/progrium/macdriver@v0.1.0/misc/variadic/variadic_amd64.go:68 +0x4d fp=0xc000374dc0 sp=0xc000374d90 pc=0x4a18ecd
github.com/progrium/macdriver/misc/variadic.(*FunctionCall).Call(0xc0001c6ea0, 0xc000198a00)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/progrium/macdriver@v0.1.0/misc/variadic/variadic_amd64.go:68 +0x2b fp=0xc000374de0 sp=0xc000374dc0 pc=0x4a18d8b
github.com/progrium/macdriver/objc.sendMsg(0x5103f58, 0xc0002777e8, 0x4c45b9b, 0x11, 0x4c3011d, 0x9, 0xc0001989f0, 0x1, 0x1, 0x0, ...)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/progrium/macdriver@v0.1.0/objc/msg_amd64.go:230 +0x705 fp=0xc000374fb8 sp=0xc000374de0 pc=0x4a1ffe5
github.com/progrium/macdriver/objc.object.SendSuper(...)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/progrium/macdriver@v0.1.0/objc/msg_amd64.go:243
github.com/progrium/macdriver/objc.(*object).SendSuper(0xc000277768, 0x4c3011d, 0x9, 0xc0001989f0, 0x1, 0x1, 0x409c614, 0xc000362390)
        <autogenerated>:1 +0xa8 fp=0xc000375020 sp=0xc000374fb8 pc=0x4a266a8
main.(*GLView).drawRect(0xc000576bb8, 0x100000000000000)
        /Users/firelizzard/Source/runway-proj/runway/cmd/runway/view_cocoa.go:186 +0xb4 fp=0xc000375080 sp=0xc000375020 pc=0x4a43c14
runtime.call16(0xc000362300, 0x4f89858, 0xc000198910, 0x1000000010)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/runtime/asm_amd64.s:550 +0x3e fp=0xc0003750a0 sp=0xc000375080 pc=0x4076f3e
reflect.Value.call(0x4adcb60, 0x4f89858, 0x13, 0x4c27666, 0x4, 0xc0004022d0, 0x2, 0x2, 0x2, 0x18, ...)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/reflect/value.go:476 +0x8e7 fp=0xc0003752a8 sp=0xc0003750a0 pc=0x40b8187
reflect.Value.Call(0x4adcb60, 0x4f89858, 0x13, 0xc0004022d0, 0x2, 0x2, 0x1, 0x2, 0x0)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/reflect/value.go:337 +0xb9 fp=0xc000375328 sp=0xc0003752a8 pc=0x40b7659
github.com/progrium/macdriver/objc.goMethodCallEntryPoint(0x7ffeefbfc040, 0x4005a1b)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/progrium/macdriver@v0.1.0/objc/call_amd64.go:273 +0x27f0 fp=0xc0003757a8 sp=0xc000375328 pc=0x4a1d2f0
_cgoexp_7aa21102d584_goMethodCallEntryPoint(0x7ffeefbfc010)
        _cgo_gotypes.go:297 +0x2e fp=0xc0003757c8 sp=0xc0003757a8 pc=0x4a2456e
runtime.cgocallbackg1(0x4a24540, 0x7ffeefbfc010, 0x0)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/runtime/cgocall.go:292 +0x18c fp=0xc000375868 sp=0xc0003757c8 pc=0x400584c
runtime.cgocallbackg(0x4a24540, 0x7ffeefbfc010, 0x0)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/runtime/cgocall.go:228 +0xda fp=0xc0003758d8 sp=0xc000375868 pc=0x400561a
runtime.cgocallback(0x40054bf, 0x4a5c050, 0xc000375970)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/runtime/asm_amd64.s:788 +0xa9 fp=0xc000375900 sp=0xc0003758d8 pc=0x4078709
runtime.asmcgocall(0x4a5c050, 0xc000375970)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/runtime/asm_amd64.s:652 +0x42 fp=0xc000375908 sp=0xc000375900 pc=0x40785e2
runtime.cgocall(0x4a5c050, 0xc000375970, 0xc000375980)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/runtime/cgocall.go:164 +0x7f fp=0xc000375940 sp=0xc000375908 pc=0x40054bf
github.com/progrium/macdriver/misc/variadic._Cfunc_VariadicCall(0xc00011e360, 0x0)
        _cgo_gotypes.go:73 +0x45 fp=0xc000375970 sp=0xc000375940 pc=0x4a18a85
github.com/progrium/macdriver/misc/variadic.(*FunctionCall).Call.func1(0xc00011e360, 0xc000375a0c)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/progrium/macdriver@v0.1.0/misc/variadic/variadic_amd64.go:68 +0x4d fp=0xc0003759a0 sp=0xc000375970 pc=0x4a18ecd
github.com/progrium/macdriver/misc/variadic.(*FunctionCall).Call(0xc00011e360, 0x76)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/progrium/macdriver@v0.1.0/misc/variadic/variadic_amd64.go:68 +0x2b fp=0xc0003759c0 sp=0xc0003759a0 pc=0x4a18d8b
github.com/progrium/macdriver/objc.sendMsg(0x5103f58, 0xc000277548, 0x4c3838b, 0xc, 0x4c2734e, 0x3, 0x0, 0x0, 0x0, 0x0, ...)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/progrium/macdriver@v0.1.0/objc/msg_amd64.go:230 +0x705 fp=0xc000375b98 sp=0xc0003759c0 pc=0x4a1ffe5
github.com/progrium/macdriver/objc.object.Send(...)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/progrium/macdriver@v0.1.0/objc/msg_amd64.go:234
github.com/progrium/macdriver/objc.(*object).Send(0xc0002774d0, 0x4c2734e, 0x3, 0x0, 0x0, 0x0, 0x5103f58, 0x561bf28)
        <autogenerated>:1 +0xa8 fp=0xc000375c00 sp=0xc000375b98 pc=0x4a265a8
github.com/progrium/macdriver/cocoa.NSApplication.Run(...)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/progrium/macdriver@v0.1.0/cocoa/NSApplication.go:51
main.viewRun(0x56a1360, 0x5708500, 0x0, 0x0)
        /Users/firelizzard/Source/runway-proj/runway/cmd/runway/view_cocoa.go:146 +0x383 fp=0xc000375cc0 sp=0xc000375c00 pc=0x4a43503
github.com/spf13/cobra.(*Command).execute(0x56a1360, 0x5708500, 0x0, 0x0, 0x56a1360, 0x5708500)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856 +0x2c2 fp=0xc000375d80 sp=0xc000375cc0 pc=0x4207a02
github.com/spf13/cobra.(*Command).ExecuteC(0x56a0960, 0x4c2a999, 0x6, 0x4c61f83)
        /Users/firelizzard/.asdf/installs/golang/1.16.2/packages/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960 +0x375 fp=0xc000375e60 sp=0xc000375d80 pc=0x4208735
main.main()
        /Users/firelizzard/Source/runway-proj/runway/cmd/runway/main.go:37 +0x21c fp=0xc000375f88 sp=0xc000375e60 pc=0x4a41fdc
runtime.main()
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/runtime/proc.go:225 +0x256 fp=0xc000375fe0 sp=0xc000375f88 pc=0x403fa56
runtime.goexit()
        /Users/firelizzard/.asdf/installs/golang/1.16.2/go/src/runtime/asm_amd64.s:1371 +0x1 fp=0xc000375fe8 sp=0xc000375fe0 pc=0x4078981

rax    0x0
rbx    0xbe5ce00
rcx    0x7ffeefbfa638
rdx    0x0
rdi    0x307
rsi    0x6
rbp    0x7ffeefbfa660
rsp    0x7ffeefbfa638
r8     0x7ffeefbfa500
r9     0x7ffeefbfa6d0
r10    0xbe5ce00
r11    0x246
r12    0x307
r13    0x3000000008
r14    0x6
r15    0x16
rip    0x7fff202e3462
rflags 0x246
cs     0x7
fs     0x0
gs     0x0
exit status 2

oh weird, if that's the case you want to submit a specific issue for SendSuper? personally, as there are a few ways to do things with the apple APIs, i just avoid anything that involves subclassing.

i wish i remember the problem i had using pthread_self that made me think it was unreliable. maybe it was related to this? anyway, i assume you know what you're doing.

For some reason that is completely unknown to me, moving all my GL calls into drawRect: works. Conversely, doing GL initialization (load textures, compile shaders, setup VBOs, etc) within the NSApp_WithDidLaunch callback seems to somehow cause all of the problems. Even if the callback was not executed on the main thread, I don't understand how that could cause SendSuper to fail, or object pointers to be invalid, or problems with Go GC... I really don't know, but I think I fixed it.

Lesson: Don't do GL outside of drawRect:. Doing GL in the NSApp_WithDidLaunch callback breaks everything in magic ways.

i assume you know what you're doing.

Haha! I wish.

All I'm doing with pthread_self is printing out the value from pthread_threadid_np. I think this should be unique per (OS) thread, and the same for a given thread. This was just a sanity check. I'm not actually using that number for anything.

Also, my NSTimer wrapper doesn't work. I add the Go callback to a sync.Map indexed on obj.Pointer(). I have an issue where map.Load(obj.Pointer()) returns nil. The only way that should happen is if the entry is deleted, which only happens in dealloc, and I put a panic in dealloc for testing. The panic didn't get hit. So for god knows what reason, my tick method is getting called with an obj.Pointer() different from the one I set it up with. So now I'm doing this:

t := time.NewTicker(16 * time.Millisecond)

go func() {
	for now := range t.C {
		core.Dispatch(func() { ... })
	}
}()

very interesting. since we're both figuring things out it might be best if you joined out discord server. https://discord.gg/P3CG6w28