fix(server): mark bare resources gone after Destroy
- commit
- 44e253e7b3442d90f34b034a4379113871345c09
- author
- brice · · 2026-09-29 04:55 UTC
- parent
- 894fe61
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +7 -2
M server/args.go +3 -1
| @@ -75,11 +75,13 @@ func (a Arg) NewID() uint32 { return uint32(a) } | |||
| 75 | 75 | // Resource returns the object argument, nil for a null object. An object | |
| 76 | 76 | // libwayland created itself (wl_registry, wl_callback of wl_display) comes | |
| 77 | 77 | // back as a bare handle: Destroy works, it has no handler, version or client. | |
| 78 | + | // Like other arguments, a bare handle is only valid during the dispatch; do | |
| 79 | + | // not retain it. | |
| 78 | 80 | func (a Arg) Resource() *Resource { | |
| 79 | 81 | if r := live.resources[uintptr(a)]; r != nil || a == 0 { | |
| 80 | 82 | return r | |
| 81 | 83 | } | |
| 82 | - | return &Resource{c: uintptr(a)} | |
| 84 | + | return &Resource{c: uintptr(a), bare: true} | |
| 83 | 85 | } | |
| 84 | 86 | ||
| 85 | 87 | // Fd returns a received file descriptor. The handler owns it and must close it. | |
| @@ -75,11 +75,13 @@ func (a Arg) NewID() uint32 { return uint32(a) } | |||||
| 75 | // Resource returns the object argument, nil for a null object. An object | 75 | // Resource returns the object argument, nil for a null object. An object | ||
| 76 | // libwayland created itself (wl_registry, wl_callback of wl_display) comes | 76 | // libwayland created itself (wl_registry, wl_callback of wl_display) comes | ||
| 77 | // back as a bare handle: Destroy works, it has no handler, version or client. | 77 | // back as a bare handle: Destroy works, it has no handler, version or client. | ||
| 78 | + | // Like other arguments, a bare handle is only valid during the dispatch; do | |||
| 79 | + | // not retain it. | |||
| 78 | func (a Arg) Resource() *Resource { | 80 | func (a Arg) Resource() *Resource { | ||
| 79 | if r := live.resources[uintptr(a)]; r != nil || a == 0 { | 81 | if r := live.resources[uintptr(a)]; r != nil || a == 0 { | ||
| 80 | return r | 82 | return r | ||
| 81 | } | 83 | } | ||
| 82 | - | return &Resource{c: uintptr(a)} | 84 | + | return &Resource{c: uintptr(a), bare: true} |
| 83 | } | 85 | } | ||
| 84 | 86 | ||||
| 85 | // Fd returns a received file descriptor. The handler owns it and must close it. | 87 | // Fd returns a received file descriptor. The handler owns it and must close it. | ||
M server/display.go +3 -0
| @@ -32,6 +32,7 @@ type Resource struct { | |||
| 32 | 32 | handler Handler | |
| 33 | 33 | OnDestroy func() | |
| 34 | 34 | gone bool | |
| 35 | + | bare bool // created by libwayland, no destroy callback | |
| 35 | 36 | ||
| 36 | 37 | // Data holds the owner's state, typically the generated wrapper. | |
| 37 | 38 | Data any | |
| @@ -286,6 +287,8 @@ func (r *Resource) Iface() *Interface { return r.iface } | |||
| 286 | 287 | func (r *Resource) Destroy() { | |
| 287 | 288 | if !r.gone { | |
| 288 | 289 | wlResourceDestroy(r.c) | |
| 290 | + | // A bare handle gets no destroy callback to mark it gone. | |
| 291 | + | r.gone = r.gone || r.bare | |
| 289 | 292 | } | |
| 290 | 293 | } | |
| 291 | 294 | ||
| @@ -32,6 +32,7 @@ type Resource struct { | |||||
| 32 | handler Handler | 32 | handler Handler | ||
| 33 | OnDestroy func() | 33 | OnDestroy func() | ||
| 34 | gone bool | 34 | gone bool | ||
| 35 | + | bare bool // created by libwayland, no destroy callback | |||
| 35 | 36 | ||||
| 36 | // Data holds the owner's state, typically the generated wrapper. | 37 | // Data holds the owner's state, typically the generated wrapper. | ||
| 37 | Data any | 38 | Data any | ||
| @@ -286,6 +287,8 @@ func (r *Resource) Iface() *Interface { return r.iface } | |||||
| 286 | func (r *Resource) Destroy() { | 287 | func (r *Resource) Destroy() { | ||
| 287 | if !r.gone { | 288 | if !r.gone { | ||
| 288 | wlResourceDestroy(r.c) | 289 | wlResourceDestroy(r.c) | ||
| 290 | + | // A bare handle gets no destroy callback to mark it gone. | |||
| 291 | + | r.gone = r.gone || r.bare | |||
| 289 | } | 292 | } | ||
| 290 | } | 293 | } | ||
| 291 | 294 | ||||
M server/display_test.go +1 -1
| @@ -44,7 +44,7 @@ func TestArgResourceUntracked(t *testing.T) { | |||
| 44 | 44 | t.Fatal("null object is not nil") | |
| 45 | 45 | } | |
| 46 | 46 | r := Arg(0x1234).Resource() | |
| 47 | - | if r == nil || r.c != 0x1234 || r.handler != nil { | |
| 47 | + | if r == nil || r.c != 0x1234 || r.handler != nil || !r.bare || !r.Alive() { | |
| 48 | 48 | t.Fatalf("untracked object %+v", r) | |
| 49 | 49 | } | |
| 50 | 50 | } | |
| @@ -44,7 +44,7 @@ func TestArgResourceUntracked(t *testing.T) { | |||||
| 44 | t.Fatal("null object is not nil") | 44 | t.Fatal("null object is not nil") | ||
| 45 | } | 45 | } | ||
| 46 | r := Arg(0x1234).Resource() | 46 | r := Arg(0x1234).Resource() | ||
| 47 | - | if r == nil || r.c != 0x1234 || r.handler != nil { | 47 | + | if r == nil || r.c != 0x1234 || r.handler != nil || !r.bare || !r.Alive() { |
| 48 | t.Fatalf("untracked object %+v", r) | 48 | t.Fatalf("untracked object %+v", r) | ||
| 49 | } | 49 | } | ||
| 50 | } | 50 | } | ||