Open sqweek opened 3 weeks ago
This is awesome detective work. I don't really have any useful comments to add. I'm running Edwood on Win and have a growing list of stuff that I need to be fixing.
Another observation -- this time I captured some register values at the start of the program (via a breakpoint on USER32!GetMessageW
):
(gdb) goroutine 1 bt
#0 runtime.cgocall (fn=0xf9e000 <runtime.asmstdcall>, arg=0x134dfc0, ~r0=<optimized out>)
at C:/env/go122/src/runtime/cgocall.go:164
#1 0x0000000000f995a7 in syscall.SyscallN (trap=<optimized out>, args=Python Exception <class 'gdb.error'>: value has been optimized out
[]uintptr,
r1=<optimized out>, r1=<optimized out>, r2=<optimized out>, r2=<optimized out>,
err=<optimized out>, err=<optimized out>) at C:/env/go122/src/runtime/syscall_windows.go:544
#2 0x0000000000f9934a in syscall.Syscall6 (fn=140722131391440, nargs=<optimized out>,
a1=<optimized out>, a2=<optimized out>, a3=6290720, a4=0, a5=0, a6=0, r1=<optimized out>,
r2=<optimized out>, err=<optimized out>) at C:/env/go122/src/runtime/syscall_windows.go:488
#3 0x0000000001089a13 in golang.org/x/exp/shiny/driver/internal/win32._GetMessage (
msg=<optimized out>, hwnd=0, msgfiltermin=0, msgfiltermax=0, ret=<optimized out>, err=...)
at C:/Users/sqweek/go/pkg/mod/golang.org/x/exp@v0.0.0-20190212162250-21964bba6549/shiny/driver/internal/win32/zsyscall_windows.go:184
#4 0x0000000001088e8b in golang.org/x/exp/shiny/driver/internal/win32.Main (
f={void (void)} 0xc000171e90, retErr=...)
at C:/Users/sqweek/go/pkg/mod/golang.org/x/exp@v0.0.0-20190212162250-21964bba6549/shiny/driver/internal/win32/win32.go:479
#5 0x000000000108db96 in golang.org/x/exp/shiny/driver/windriver.Main (
f={void (golang.org/x/exp/shiny/screen.Screen)} 0xc000171ec0)
at C:/Users/sqweek/go/pkg/mod/golang.org/x/exp@v0.0.0-20190212162250-21964bba6549/shiny/driver/windriver/windriver.go:22
#6 0x0000000001093790 in golang.org/x/exp/shiny/driver.main (
f={void (golang.org/x/exp/shiny/screen.Screen)} 0x0)
at C:/Users/sqweek/go/pkg/mod/golang.org/x/exp@v0.0.0-20190212162250-21964bba6549/shiny/driver/driver_windows.go:13
#7 golang.org/x/exp/shiny/driver.Main (f={void (golang.org/x/exp/shiny/screen.Screen)} 0x0)
at C:/Users/sqweek/go/pkg/mod/golang.org/x/exp@v0.0.0-20190212162250-21964bba6549/shiny/driver/d--Type <RET> for more, q to quit, c to continue without paging--
river.go:24
#8 github.com/ktye/duitdraw.Main (f={void (github.com/ktye/duitdraw.Device *)} 0xc000171ee0)
at C:/Users/sqweek/go/pkg/mod/github.com/ktye/duitdraw@v0.0.0-20190328070634-a54e9bd5a862/init.go:28
#9 0x00000000010ddf76 in github.com/rjkroege/edwood/draw.Main (
f={void (github.com/rjkroege/edwood/draw.Device *)} 0xc000171f28)
at C:/Users/sqweek/go/pkg/mod/github.com/rjkroege/edwood@v0.3.1/draw/duitdraw.go:53
#10 main.main () at C:/Users/sqweek/go/pkg/mod/github.com/rjkroege/edwood@v0.3.1/acme.go:79
(gdb) info register
rax 0x7ffc6ca753d0 140722131391440
rbx 0x134dfc0 20242368
rcx 0xc000171e28 824635235880
rdx 0x0 0
rsi 0x5ffd20 6290720
rdi 0x5ffd50 6290768
rbp 0x5ffe80 0x5ffe80
rsp 0x5ffcc0 0x5ffcc0
...
Note rcx
is the pointer to the message struct in this case as we are at the start of the GetMessageW function; it gets moved into rbx
later.
And then at the time of the crash:
(gdb) goroutine 1 bt
#0 runtime.cgocall (fn=0xf9e000 <runtime.asmstdcall>, arg=0x134dfc0, ~r0=<optimized out>)
at C:/env/go122/src/runtime/cgocall.go:164
#1 0x0000000000f995a7 in syscall.SyscallN (trap=<optimized out>, args=Python Exception <class 'gdb.error'>: value has been optimized out
[]uintptr,
r1=<optimized out>, r1=<optimized out>, r2=<optimized out>, r2=<optimized out>,
err=<optimized out>, err=<optimized out>) at C:/env/go122/src/runtime/syscall_windows.go:544
#2 0x0000000000f9934a in syscall.Syscall6 (fn=0, nargs=<optimized out>, a1=<optimized out>,
a2=<optimized out>, a3=6290720, a4=6290616, a5=0, a6=0, r1=<optimized out>,
r2=<optimized out>, err=<optimized out>) at C:/env/go122/src/runtime/syscall_windows.go:488
#3 0x0000000001089a13 in golang.org/x/exp/shiny/driver/internal/win32._GetMessage (
msg=<optimized out>, hwnd=0, msgfiltermin=0, msgfiltermax=0, ret=<optimized out>, err=...)
at C:/Users/sqweek/go/pkg/mod/golang.org/x/exp@v0.0.0-20190212162250-21964bba6549/shiny/driver/internal/win32/zsyscall_windows.go:184
#4 0x0000000001088e8b in golang.org/x/exp/shiny/driver/internal/win32.Main (
f={void (void)} 0xc000583e90, retErr=...)
at C:/Users/sqweek/go/pkg/mod/golang.org/x/exp@v0.0.0-20190212162250-21964bba6549/shiny/driver/internal/win32/win32.go:479
#5 0x000000000108db96 in golang.org/x/exp/shiny/driver/windriver.Main (
f={void (golang.org/x/exp/shiny/screen.Screen)} 0xc000583ec0)
at C:/Users/sqweek/go/pkg/mod/golang.org/x/exp@v0.0.0-20190212162250-21964bba6549/shiny/driver/windriver/windriver.go:22
#6 0x0000000001093790 in golang.org/x/exp/shiny/driver.main (
f={void (golang.org/x/exp/shiny/screen.Screen)} 0x0)
at C:/Users/sqweek/go/pkg/mod/golang.org/x/exp@v0.0.0-20190212162250-21964bba6549/shiny/driver/driver_windows.go:13
#7 golang.org/x/exp/shiny/driver.Main (f={void (golang.org/x/exp/shiny/screen.Screen)} 0x0)
at C:/Users/sqweek/go/pkg/mod/golang.org/x/exp@v0.0.0-20190212162250-21964bba6549/shiny/driver/d--Type <RET> for more, q to quit, c to continue without paging--
river.go:24
#8 github.com/ktye/duitdraw.Main (f={void (github.com/ktye/duitdraw.Device *)} 0xc000583ee0)
at C:/Users/sqweek/go/pkg/mod/github.com/ktye/duitdraw@v0.0.0-20190328070634-a54e9bd5a862/init.go:28
#9 0x00000000010ddf76 in github.com/rjkroege/edwood/draw.Main (
f={void (github.com/rjkroege/edwood/draw.Device *)} 0xc000583f28)
at C:/Users/sqweek/go/pkg/mod/github.com/rjkroege/edwood@v0.3.1/draw/duitdraw.go:53
#10 main.main () at C:/Users/sqweek/go/pkg/mod/github.com/rjkroege/edwood@v0.3.1/acme.go:79
(gdb) p $_siginfo
$2 = {ExceptionCode = ACCESS_VIOLATION, ExceptionFlags = 0, ExceptionRecord = 0x0,
ExceptionAddress = 0x7ffc6ca7540e <USER32!GetMessageW+62>, NumberParameters = 2, {
ExceptionInformation = {0, 824638201392, 0 <repeats 13 times>}, AccessViolationInformation = {
Type = READ_ACCESS_VIOLATION, Address = 0xc000445e30}}}
(gdb) info register
rax 0x0 0
rbx 0xc000445e28 824638201384
rcx 0x7ffc6afa1534 140722103260468
rdx 0x0 0
rsi 0x5ffd20 6290720
rdi 0x0 0
rbp 0x5ffe80 0x5ffe80
rbx
is definitely not pointing at the same MSG struct that we started with. Looking at the go stack trace I also notice that the duitdraw.Device and screen.Screen pointers are different which I find a bit surprising -- suggests that multiple event loops are running?
My laptop does have two screens built in and also two GPUs, I wonder if that's somehow related. Will investigate this angle and also delve
for go debugging when I have time
Ok delve doesn't seem useful for debugging segfaults on windows, I just get this:
(dlv) continue
«... time passes ...»
Process 43252 has exited with status 3221225477
(dlv) bt
Process 43252 has exited with status 3221225477
(dlv) goroutine 1
Process 43252 has exited with status 3221225477
(dlv) dump t.core
Dumping memory 0 / 0...
error dumping: Internal debugger error: send on closed channel
runtime.gopanic (0xe6cad1)
C:/env/go122/src/runtime/panic.go:770
runtime.chansend (0xe39f07)
C:/env/go122/src/runtime/chan.go:206
runtime.chansend1 (0xe39996)
C:/env/go122/src/runtime/chan.go:145
github.com/go-delve/delve/pkg/proc/native.(*nativeProcess).execPtraceFunc (0x12d5d1a)
C:/Users/sqweek/go/pkg/mod/github.com/go-delve/delve@v1.23.0/pkg/proc/native/proc.go:412
github.com/go-delve/delve/pkg/proc/native.(*nativeProcess).MemoryMap (0x12d5ca9)
C:/Users/sqweek/go/pkg/mod/github.com/go-delve/delve@v1.23.0/pkg/proc/native/dump_windows_amd64.go:16
github.com/go-delve/delve/pkg/proc.(*Target).Dump (0x11fdc69)
C:/Users/sqweek/go/pkg/mod/github.com/go-delve/delve@v1.23.0/pkg/proc/dump.go:190
github.com/go-delve/delve/service/debugger.(*Debugger).DumpStart.func1 (0x12f2c6b)
C:/Users/sqweek/go/pkg/mod/github.com/go-delve/delve@v1.23.0/service/debugger/debugger.go:2307
runtime.goexit (0xea0c40)
C:/env/go122/src/runtime/asm_amd64.s:1695
A quick search suggested that setting a breakpoint when a signal is received is not yet supported by delve.
I thought perhaps I could use gdb to capture the segfault then save a core file for delve to read, but gdb on windows cannot generate core files :S
Ok I've managed to get delve to print out the _MSG struct at every invocation of shiny/driver/internal/win32._GetMessage()
, hopefully that will log something useful for the next crash
hopefully that will log something useful for the next crash
Unfortunately, it did not :( Just some WM_MOUSEMOVE messages:
> goroutine(1): golang.org/x/exp/shiny/driver/internal/win32._GetMessage(("*golang.org/x/exp/shiny/driver/internal/win32._MSG")(0xc000623e28), 0, 0, 0)
msg: ("*golang.org/x/exp/shiny/driver/internal/win32._MSG")(0xc000623e28)
*golang.org/x/exp/shiny/driver/internal/win32._MSG {
HWND: 19796938,
Message: 512,
Wparam: 0,
Lparam: 5505729,
Time: 1796106968,
Pt: golang.org/x/exp/shiny/driver/internal/win32._POINT {X: 2498, Y: 374},}
> goroutine(1): golang.org/x/exp/shiny/driver/internal/win32._GetMessage(("*golang.org/x/exp/shiny/driver/internal/win32._MSG")(0xc000623e28), 0, 0, 0)
msg: ("*golang.org/x/exp/shiny/driver/internal/win32._MSG")(0xc000623e28)
*golang.org/x/exp/shiny/driver/internal/win32._MSG {
HWND: 19796938,
Message: 512,
Wparam: 0,
Lparam: 5178062,
Time: 1796106968,
Pt: golang.org/x/exp/shiny/driver/internal/win32._POINT {X: 2511, Y: 369},}
> goroutine(1): golang.org/x/exp/shiny/driver/internal/win32._GetMessage(("*golang.org/x/exp/shiny/driver/internal/win32._MSG")(0xc000623e28), 0, 0, 0)
msg: ("*golang.org/x/exp/shiny/driver/internal/win32._MSG")(0xc000623e28)
*golang.org/x/exp/shiny/driver/internal/win32._MSG {
HWND: 19796938,
Message: 512,
Wparam: 0,
Lparam: 4588260,
Time: 1796106984,
Pt: golang.org/x/exp/shiny/driver/internal/win32._POINT {X: 2533, Y: 360},}
Process 63676 has exited with status 3221225477
I'm a bit at a loss. I haven't had to move windows between screens or switch between battery/AC power to trigger the crash, sometimes it happens just a few minutes after opening edwood
I'm seeing a regular segfault on Win11. It seems to happen when edwood does not have focus and the mouse pointer passes over it, but I don't have a solid reproducer yet.
I'm not really expecting any help solving this one, I'm mainly filing the issue so I have a place to keep notes. From what I've gathered so far it looks like this might actually be an exp/shiny bug, however I couldn't find an issue tracker for that project.
Without further ado, the crash looks like this from gdb's perspective (I also need to look into delve):
Ie. we're in exp/shiny's win32 message loop which looks very standard:
It's hard to see how edwood could influence this codepath, unless shiny somehow leaks a pointer into the _MSG struct into its event handlers.
Digging deeper into the native side of the core:
On the shiny side we have:
which plumbs into the standard library runtime/syscall_windows.go:
From what I can tell from reading
sys_windows_amd64.s
andos_windows.go
,asmstdcall()
puts the first argument into the CX register. According to the disassembly USER32!GetMessageW moves RCX into RBX and then tries to access memory near RBX which is responsible for the segfault. ie. this corresponds to the_MSG
struct passed in by shiny. However I've no clue why that would suddenly become inaccessible so I wonder if I've taken a wrong turn somewhere.Anyway that will do for now, it's past my bedtime ;)