Please discard the previous PR.
On macOS, it seems like CFRunLoopTimerInvalidate()
doesn't prevent already-queued timer callbacks from firing.
This can cause crashes when a wxTimer()
is invoked after Stop() or the destructor has been called, as the timer object may have been destroyed.
This fix adds a validity check using CFRunLoopTimerIsValid()
before processing the callback, ensuring we don't dereference invalid timer pointers.
This crash was observed in CodeBlocks IDE on macOS where timer events would occasionally fire after cleanup:
VM Region Info: 0x1 is not in any region. Bytes before following region: 4363567103
REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
UNUSED SPACE AT START
--->
__TEXT 10416c000-104354000 [ 1952K] r-x/r-x SM=COW /Applications/CodeBlocks.app/Contents/MacOS/codeblocks
Application Specific Information:
abort() called
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x188452388 __pthread_kill + 8
1 libsystem_pthread.dylib 0x18848b88c pthread_kill + 296
2 libsystem_c.dylib 0x188394a3c abort + 124
3 libwx_baseu-3.2.0.dylib 0x1051f06b8 wxFatalSignalHandler(int) + 52 (utilsunx.cpp:1522)
4 libsystem_platform.dylib 0x1884c56a4 _sigtramp + 56
5 libwx_osx_cocoau_core-3.2.0.dylib 0x105bb3498 wxTimerImpl::Notify() + 36 (timer.h:47)
6 libwx_osx_cocoau_core-3.2.0.dylib 0x105bb2e54 wxProcessTimer(__CFRunLoopTimer*, void*) + 96 (timer.cpp:38)
7 CoreFoundation 0x18858fc50 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 32
8 CoreFoundation 0x18858f910 __CFRunLoopDoTimer + 980
9 CoreFoundation 0x18858f44c __CFRunLoopDoTimers + 332
10 CoreFoundation 0x188575858 __CFRunLoopRun + 1848
11 CoreFoundation 0x188574a98 CFRunLoopRunSpecific + 572
12 HIToolbox 0x19401727c RunCurrentEventLoopInMode + 324
13 HIToolbox 0x19401a31c ReceiveNextEventCommon + 216
14 HIToolbox 0x1941a5484 _BlockUntilNextEventMatchingListInModeWithFilter + 76
15 AppKit 0x18c499a34 _DPSNextEvent + 684
16 AppKit 0x18ce38940 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 688
17 libwx_osx_cocoau_core-3.2.0.dylib 0x105c684f8 wxGUIEventLoop::OSXDoRun() + 288 (evtloop.mm:319)
18 libwx_baseu-3.2.0.dylib 0x1051cc4b0 wxCFEventLoop::DoRun() + 44 (evtloop_cf.cpp:326)
19 libwx_baseu-3.2.0.dylib 0x1050de824 wxEventLoopBase::Run() + 248 (evtloopcmn.cpp:87)
20 libwx_baseu-3.2.0.dylib 0x1051f0894 wxAppTraits::RunLoopUntilChildExit(wxExecuteData&, wxEventLoopBase&) + 356 (utilsunx.cpp:1635)
21 libwx_osx_cocoau_core-3.2.0.dylib 0x105b837cc wxGUIAppTraits::WaitForChild(wxExecuteData&) + 104 (apptraits.cpp:46)
22 libwx_baseu-3.2.0.dylib 0x1051edb34 wxExecute(char const* const*, int, wxProcess*, wxExecuteEnv const*) + 6124 (utilsunx.cpp:890)
23 libwx_baseu-3.2.0.dylib 0x1051ec090 wxExecute(wxString const&, int, wxProcess*, wxExecuteEnv const*) + 108 (utilsunx.cpp:508)
24 libwx_baseu-3.2.0.dylib 0x1051c0584 wxDoExecuteWithCapture(wxString const&, wxArrayString&, wxArrayString*, int, wxExecuteEnv const*) + 104 (utilscmn.cpp:653)
25 libwx_baseu-3.2.0.dylib 0x1051c0510 wxExecute(wxString const&, wxArrayString&, int, wxExecuteEnv const*) + 52 (utilscmn.cpp:680)
26 libcodeblocks.dylib 0x1073d0f2c cbExpandBackticks(wxString&) + 1164 (globals.cpp:911)
27 libcodeblocks.dylib 0x107339af4 CompilerCommandGenerator::SetupLinkerOptions(Compiler*, ProjectBuildTarget*) + 644 (compilercommandgenerator.cpp:1050)
28 libcodeblocks.dylib 0x107331748 CompilerCommandGenerator::Init(cbProject*) + 3416 (compilercommandgenerator.cpp:165)
29 libcodeblocks.dylib 0x10731ef68 Compiler::GetCommandGenerator(cbProject*) + 68 (compiler.cpp:302)
30 codecompletion.dylib 0x121859080 ParseManager::AddCompilerDirs(cbProject*, ParserBase*) + 240 (parsemanager.cpp:1872)
31 codecompletion.dylib 0x1218519c0 ParseManager::DoFullParsing(cbProject*, ParserBase*) + 92 (parsemanager.cpp:1101)
32 codecompletion.dylib 0x1218515f8 ParseManager::CreateParser(cbProject*) + 260 (parsemanager.cpp:567)
33 codecompletion.dylib 0x1217f9260 CodeCompletion::OnWorkspaceChanged(CodeBlocksEvent&) + 124 (codecompletion.cpp:2235)
34 codecompletion.dylib 0x121813fd8 cbEventFunctor<CodeCompletion, CodeBlocksEvent>::Call(CodeBlocksEvent&) + 128 (cbfunctor.h:49)
35 libcodeblocks.dylib 0x1073f7eec Manager::ProcessEvent(CodeBlocksEvent&) + 244 (manager.cpp:268)
36 libcodeblocks.dylib 0x1074282a8 PluginManager::NotifyPlugins(CodeBlocksEvent&) + 32 (pluginmanager.cpp:1628)
37 libcodeblocks.dylib 0x1074683fc ProjectManager::WorkspaceChanged() + 140 (projectmanager.cpp:1022)
38 libcodeblocks.dylib 0x107469834 ProjectManager::EndLoadingWorkspace() + 1788 (projectmanager.cpp:1201)
39 libcodeblocks.dylib 0x107468f38 ProjectManager::LoadWorkspace(wxString const&) + 152 (projectmanager.cpp:586)
40 codeblocks 0x1042355b0 0x10416c000 + 824752
41 codeblocks 0x104221f9c 0x10416c000 + 745372
42 libwx_baseu-3.2.0.dylib 0x105092760 wxAppConsoleBase::HandleEvent(wxEvtHandler*, void (wxEvtHandler::*)(wxEvent&), wxEvent&) const + 148 (appbase.cpp:678)
43 libwx_baseu-3.2.0.dylib 0x10509280c wxAppConsoleBase::CallEventHandler(wxEvtHandler*, wxEventFunctor&, wxEvent&) const + 160 (appbase.cpp:690)
44 libwx_baseu-3.2.0.dylib 0x1051b702c wxEvtHandler::ProcessEventIfMatchesId(wxEventTableEntryBase const&, wxEvtHandler*, wxEvent&) + 252 (event.cpp:1482)
45 libwx_baseu-3.2.0.dylib 0x1051b6d80 wxEventHashTable::HandleEvent(wxEvent&, wxEvtHandler*) + 272 (event.cpp:1087)
46 libwx_baseu-3.2.0.dylib 0x1051b9004 wxEvtHandler::TryHereOnly(wxEvent&) + 144 (event.cpp:1679)
47 libwx_baseu-3.2.0.dylib 0x1051b8d38 wxEvtHandler::TryBeforeAndHere(wxEvent&) + 72 (event.h:4013)
48 libwx_baseu-3.2.0.dylib 0x1051b8d78 wxEvtHandler::ProcessEventLocally(wxEvent&) + 36 (event.cpp:1612)
49 libwx_baseu-3.2.0.dylib 0x1051b8bec wxEvtHandler::ProcessEvent(wxEvent&) + 360 (event.cpp:1585)
50 libwx_baseu-3.2.0.dylib 0x1051b86dc wxEvtHandler::SafelyProcessEvent(wxEvent&) + 40 (event.cpp:1701)
51 libwx_baseu-3.2.0.dylib 0x1051b8638 wxEvtHandler::ProcessPendingEvents() + 1100 (event.cpp:1449)
52 libwx_baseu-3.2.0.dylib 0x10509225c wxAppConsoleBase::ProcessPendingEvents() + 240 (appbase.cpp:587)
53 libwx_baseu-3.2.0.dylib 0x1051cba84 wxCFEventLoop::CommonModeObserverCallBack(__CFRunLoopObserver*, int) + 88 (evtloop_cf.cpp:95)
54 libwx_baseu-3.2.0.dylib 0x1051cba1c wxCFEventLoop::OSXCommonModeObserverCallBack(__CFRunLoopObserver*, int, void*) + 76 (evtloop_cf.cpp:72)
55 CoreFoundation 0x188575ed8 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36
56 CoreFoundation 0x188575dc0 __CFRunLoopDoObservers + 536
57 CoreFoundation 0x188575430 __CFRunLoopRun + 784
58 CoreFoundation 0x188574a98 CFRunLoopRunSpecific + 572
59 HIToolbox 0x19401727c RunCurrentEventLoopInMode + 324
60 HIToolbox 0x19401a31c ReceiveNextEventCommon + 216
61 HIToolbox 0x1941a5484 _BlockUntilNextEventMatchingListInModeWithFilter + 76
62 AppKit 0x18c499a34 _DPSNextEvent + 684
63 AppKit 0x18ce38940 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 688
64 AppKit 0x18c48cbe4 -[NSApplication run] + 480
65 libwx_osx_cocoau_core-3.2.0.dylib 0x105c68478 wxGUIEventLoop::OSXDoRun() + 160 (evtloop.mm:301)
66 libwx_baseu-3.2.0.dylib 0x1051cc4b0 wxCFEventLoop::DoRun() + 44 (evtloop_cf.cpp:326)
67 libwx_baseu-3.2.0.dylib 0x1050de824 wxEventLoopBase::Run() + 248 (evtloopcmn.cpp:87)
68 libwx_baseu-3.2.0.dylib 0x105091400 wxAppConsoleBase::MainLoop() + 168 (appbase.cpp:395)
69 libwx_baseu-3.2.0.dylib 0x105090f10 wxAppConsoleBase::OnRun() + 32 (appbase.cpp:317)
70 libwx_osx_cocoau_core-3.2.0.dylib 0x105888160 wxAppBase::OnRun() + 64 (appcmn.cpp:334)
71 libwx_osx_cocoau_core-3.2.0.dylib 0x105be36dc wxApp::OnRun() + 40 (app.cpp:364)
72 codeblocks 0x104174414 0x10416c000 + 33812
73 libwx_baseu-3.2.0.dylib 0x10511d638 wxEntry(int&, wchar_t**) + 304 (init.cpp:497)
74 libwx_baseu-3.2.0.dylib 0x10511d7f8 wxEntry(int&, char**) + 56 (init.cpp:509)
75 codeblocks 0x10416cbe0 0x10416c000 + 3040
76 dyld 0x1880eab98 start + 6076
https://github.com/wxWidgets/wxWidgets/pull/25871
(1 file)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
Thanks for the PR and explanations!
This looks correct to me and not so different from what I had to do in wxTimerWndProc
in wxMSW (except I had to use my own container of valid timers as Win32 doesn't have any equivalent of CFRunLoopTimerIsValid()
).
@csomor Do you have any objections/comments? If not, I'll merge this soon (and backport to 3.2).
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@csomor approved this pull request.
Perfect, I didn't know that, thanks a lot!
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.