-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
win32: Window.buffer manipulation is racy, can panic on minimisation #52
Comments
I had issue like that with passing uintptr to slice data when I was working on my go-powered hypervisor. So I think that uintptr(unsafe.Pointer(&lpvBits[0])) also could be changed to: uintptr(([3]unsafe.Pointer)(unsafe.Pointer(&lpvBits))[0]) so we resolve the array field instead of first slice index |
Hrm, thanks. Can you elaborate on the difference between the two and why it caused problems? Logically they appear to represent the same thing to me, and a quick test gives me the same value for both: package main
(this is all something of a tangent since this cast happens in the AllenDang/w32 package rather than go.wde) |
sorry for the delay basically, in normal case it should give the same value, but my way to do that will work even if package main
import "unsafe"
func main() {
a := make([]int, 0)
// println(uintptr(unsafe.Pointer(&a[0]))) // uncomment to break the program
println(uintptr((*[3]unsafe.Pointer)(unsafe.Pointer(&a))[0])) // works like a charm
} let's look into evaluation stages to see the difference:
println(uintptr(unsafe.Pointer(&a[0]))) stage 1. breaks if a.array len == 0. println(uintptr(unsafe.Pointer(&a.array[0]))) stage 2. optimize, round 1 println(uintptr(unsafe.Pointer(a.array))) stage 3. opimize, round 2. unnecessary unsafe.Pointer to unsafe.Pointer conversion println(uintptr(a.array))
println(uintptr((*[3]unsafe.Pointer)(unsafe.Pointer(&a))[0])) let's just make it simple to read package main
import (
"unsafe"
"github.com/gramework/runtimer"
)
func main() {
a := make([]int, 0)
println(uintptr((*runtimer.SliceType2)(unsafe.Pointer(&a)).Array))
} split on stages: package main
import (
"unsafe"
"github.com/gramework/runtimer"
)
func main() {
a := make([]int, 0)
aPtr := unsafe.Pointer(&a)
runtimeSlice := (*runtimer.SliceType2)(aPtr)
aArrayPtr := runtimeSlice.Array
println(uintptr(aArrayPtr))
} |
Ah I see... I guess the Array field resolves to nil in the zero length slice case? Anyway I think we should just avoid calling SetDIBitsToDevice with an empty slice here, but thanks for the details! |
yep |
I've seen it panic once when minimising a window, like so:
It's index 0:
lpvBits
corresponds tobuffer.Pix
inWindow.blitImage
, indicating that we have a zero-length pixel array.FlushImage
tries to avoid this scenario (since #46):So I guess
this.buffer
must be changing concurrently. I'm callingFlushImage
from a different goroutine than the one handlingEventChan
but I think it's racy even without that sinceWindow.buffer
is changed whenWndProc
handles aWM_SIZE
message, before theResizeEvent
is posted. Even the EventChan thread may observe the change to buffer before seeing the ResizeEvent.The text was updated successfully, but these errors were encountered: