From 463fa72c307aa522e5cff70d4770aea8de5b8679 Mon Sep 17 00:00:00 2001 From: Snider Date: Fri, 17 Apr 2026 19:33:54 +0100 Subject: [PATCH] Harden stub callback dispatch --- stubs/wails/pkg/application/events.go | 13 ++++++++++++- stubs/wails/pkg/application/events_test.go | 15 +++++++++++++++ stubs/wails/pkg/application/keybinding.go | 10 ++++++++-- stubs/wails/pkg/application/keybinding_test.go | 10 ++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/stubs/wails/pkg/application/events.go b/stubs/wails/pkg/application/events.go index b89f6e36..f4b389f8 100644 --- a/stubs/wails/pkg/application/events.go +++ b/stubs/wails/pkg/application/events.go @@ -154,11 +154,22 @@ func (em *EventManager) Emit(name string, data ...any) bool { if event.IsCancelled() { break } - listener.callback(event) + invokeCustomEventListener(listener, event) } return event.IsCancelled() } +func invokeCustomEventListener(listener *customEventListener, event *CustomEvent) { + if listener == nil || listener.callback == nil || event == nil { + return + } + + defer func() { + _ = recover() + }() + listener.callback(event) +} + // On registers a persistent listener for the named custom event. // Returns a cancellation function that removes the listener. // diff --git a/stubs/wails/pkg/application/events_test.go b/stubs/wails/pkg/application/events_test.go index 818f7aa1..fcd433f1 100644 --- a/stubs/wails/pkg/application/events_test.go +++ b/stubs/wails/pkg/application/events_test.go @@ -98,6 +98,21 @@ func TestEvents_EventManager_Emit_Ugly(t *testing.T) { assert.Equal(t, 1, calls) } +func TestEvents_EventManager_Emit_RecoversFromPanic(t *testing.T) { + manager := newEventManager() + calls := 0 + + manager.On("ready", func(*CustomEvent) { + panic("boom") + }) + manager.On("ready", func(*CustomEvent) { + calls++ + }) + + assert.False(t, manager.Emit("ready")) + assert.Equal(t, 1, calls) +} + func TestEvents_EventManager_OnApplicationEvent_Good(t *testing.T) { manager := newEventManager() eventType := events.ApplicationEventType(42) diff --git a/stubs/wails/pkg/application/keybinding.go b/stubs/wails/pkg/application/keybinding.go index c190bf09..5e06fd5f 100644 --- a/stubs/wails/pkg/application/keybinding.go +++ b/stubs/wails/pkg/application/keybinding.go @@ -43,13 +43,19 @@ func (m *KeyBindingManager) Remove(accelerator string) { // Process fires the callback for the given accelerator and returns true if handled. // // if manager.Process("CmdOrCtrl+K", window) { return } -func (m *KeyBindingManager) Process(accelerator string, window Window) bool { +func (m *KeyBindingManager) Process(accelerator string, window Window) (handled bool) { m.mu.RLock() callback, exists := m.bindings[accelerator] m.mu.RUnlock() if exists && callback != nil { + handled = true + defer func() { + if recover() != nil { + handled = false + } + }() callback(window) - return true + return } return false } diff --git a/stubs/wails/pkg/application/keybinding_test.go b/stubs/wails/pkg/application/keybinding_test.go index 1de1814b..ed330b1f 100644 --- a/stubs/wails/pkg/application/keybinding_test.go +++ b/stubs/wails/pkg/application/keybinding_test.go @@ -44,6 +44,16 @@ func TestKeyBindingManager_Add_Ugly(t *testing.T) { assert.Equal(t, 10, calls) } +func TestKeyBindingManager_Process_RecoversFromPanic(t *testing.T) { + manager := &KeyBindingManager{} + + manager.Add("CmdOrCtrl+K", func(Window) { + panic("boom") + }) + + assert.False(t, manager.Process("CmdOrCtrl+K", nil)) +} + func TestKeyBindingManager_Remove_Good(t *testing.T) { manager := &KeyBindingManager{} manager.Add("CmdOrCtrl+K", func(Window) {})