1
C / Crash after closing wxMac with SFML-window
« on: January 21, 2019, 06:41:53 pm »
*System specification are as follow...
macOS Mojave -> Mac OS X 10.14.2
wxWidgets 3.1.2 -> --with-osx_cocoa --with-macosx-version-min=10.14 --with-macosx=MacOSX10.14.sdk
SFML 2.5.1 -> macOS OS X 10.7+, compatible with C++11 and libc++
The following code snippet, shown below, comes from a GitHub project that you can find at this link https://gist.github.com/eriknelson/e4ccf32534eb3d25a1ea. Please give Eriknelson credit for his SFML 2.3+ into wxWidgets 3.0 integration demo. This demo is not prefect but it only has one flaw. The application crashes after closing the wxWidgets window.
His example runs as expected but upon closing the wxWidgets windows it crashes with the following error shown below.
I suspect wxControl and sf::RenderWindows are trying the close the NSView, which comes from the GetHandle() call, at the same time. Before I start dissecting through wxWidgets and SFML source with a debugger, I would like to ask if anyone here have a solution for gracefully handling this scenario.
Meanwhile, I will be actively debugging this issue while this forum post is active. If I find a solution first, I will most definitely update this post with the solution as reference for all who have or will encounter this issue in the future.
-James Harris
macOS Mojave -> Mac OS X 10.14.2
wxWidgets 3.1.2 -> --with-osx_cocoa --with-macosx-version-min=10.14 --with-macosx=MacOSX10.14.sdk
SFML 2.5.1 -> macOS OS X 10.7+, compatible with C++11 and libc++
The following code snippet, shown below, comes from a GitHub project that you can find at this link https://gist.github.com/eriknelson/e4ccf32534eb3d25a1ea. Please give Eriknelson credit for his SFML 2.3+ into wxWidgets 3.0 integration demo. This demo is not prefect but it only has one flaw. The application crashes after closing the wxWidgets window.
Code: [Select]
#include <iostream>
#include <wx/wx.h>
#include <memory>
#include <SFML/Graphics.hpp>
#ifdef __WXGTK__
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#endif
using namespace std;
static const int kDefaultWindowWidth = 1280;
static const int kDefaultWindowHeight = 720;
static const int kCanvasMargin = 0;
struct wxSfmlCanvas : public wxControl, public sf::RenderWindow
{
wxSfmlCanvas(
wxWindow *parent = nullptr,
wxWindowID windowId = -1,
const wxPoint &position = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = 0) :
wxControl(parent, windowId, position, size, style)
{
createRenderWindow();
}
virtual void onUpdate(){};
void onIdle(wxIdleEvent& event)
{
// Send a paint message when control is idle, to ensure max framerate
Refresh();
}
void onPaint(wxPaintEvent& event)
{
wxPaintDC dc(this); // Prepare control to be repainted
onUpdate(); // Tick update
display(); // Draw
}
// Explicitly overriding prevents wxWidgets from drawing, which could result in flicker
void onEraseBackground(wxEraseEvent& event){}
void createRenderWindow()
{
#ifdef __WXGTK__
// gtk_widget_realize(m_wxwindow);
// gtk_widget_set_double_buffered(m_wxwindow, false);
// GdkWindow *gdkWindow = gtk_widget_get_window((GtkWidget*)GetHandle());
// XFlush(GDK_WINDOW_XDISPLAY(gdkWindow));
// sf::RenderWindow::create(GDK_WINDOW_XWINDOW(gdkWindow));
#else
sf::RenderWindow::create(GetHandle());
#endif
}
void setwxWindowSize(const wxSize& size)
{
this->SetSize(size);
}
void setRenderWindowSize(const sf::Vector2u& size)
{
this->setSize(size);
}
virtual ~wxSfmlCanvas(){};
wxDECLARE_EVENT_TABLE();
};
struct Canvas : public wxSfmlCanvas
{
Canvas(
wxWindow* parent,
wxWindowID id,
wxPoint position,
wxSize size,
long style = 0) :
wxSfmlCanvas(parent, id, position, size, style)
{
}
virtual void onUpdate()
{
clear(sf::Color::Yellow);
sf::CircleShape shape(50);
shape.setFillColor(sf::Color(150, 50, 250));
shape.setOutlineThickness(10);
shape.setOutlineColor(sf::Color(250, 150, 100));
sf::RectangleShape line(sf::Vector2f(150, 5));
line.rotate(45);
this->draw(shape);
this->draw(line);
}
void onResize(wxSizeEvent& event)
{
auto size = event.GetSize();
auto newCanvasWidth = size.x - (2 * kCanvasMargin);
auto newCanvasHeight = size.y - (2 * kCanvasMargin);
sf::Vector2u v(newCanvasWidth,newCanvasHeight);
wxSize s(newCanvasWidth,newCanvasHeight);
this->SetSize(s); //wx setSize
this->setSize(v); //SFML setSize
}
};
struct AppFrame : public wxFrame
{
AppFrame(const wxString& title, const wxPoint& pos, const wxSize& size) :
wxFrame(NULL, wxID_ANY, title, pos, size),
_panel(new wxPanel(this)),
_canvas(new Canvas(
_panel.get(),
wxID_ANY,
wxPoint(kCanvasMargin, kCanvasMargin),
wxSize(kDefaultWindowWidth - (2 * kCanvasMargin), kDefaultWindowHeight - (2 * kCanvasMargin))
))
{
_panel->SetBackgroundColour(*wxCYAN);
////////////////////////////////////////////////////////////////////////////////
// Probably due to some RTTI, IDE is getting confused by this dynamic call
// and doesn't understand the correct Bind overload. Causes non sequitur errors
// to display in the inspector. Suppress.
//
// Dynamic binding is cleanest here, since we don't want to hook up our resize
// handler until our dependencies (Canvas namely) have finished their initialization
////////////////////////////////////////////////////////////////////////////////
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wint-conversion"
Bind(wxEVT_SIZE, &AppFrame::onResize, this);
#pragma clang diagnostic pop
////////////////////////////////////////////////////////////////////////////////
}
void onResize(wxSizeEvent& event)
{
_canvas->onResize(event);
event.Skip();
}
unique_ptr<wxPanel> _panel;
unique_ptr<Canvas> _canvas;
};
struct App : public wxApp
{
virtual bool OnInit()
{
auto frame = new AppFrame("SFML Canvas Demo", wxPoint(100, 100),
wxSize(kDefaultWindowWidth, kDefaultWindowHeight));
frame->Show(true);
return true;
}
};
wxBEGIN_EVENT_TABLE(wxSfmlCanvas, wxControl)
EVT_IDLE(wxSfmlCanvas::onIdle)
EVT_PAINT(wxSfmlCanvas::onPaint)
EVT_ERASE_BACKGROUND(wxSfmlCanvas::onEraseBackground)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(App);
His example runs as expected but upon closing the wxWidgets windows it crashes with the following error shown below.
Code: [Select]
rashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: Namespace OBJC, Code 0x1
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x00007fff64e7c01e __abort_with_payload + 10
1 libsystem_kernel.dylib 0x00007fff64e77541 abort_with_payload_wrapper_internal + 82
2 libsystem_kernel.dylib 0x00007fff64e774ef abort_with_reason + 22
3 libobjc.A.dylib 0x00007fff63c58674 _objc_fatalv(unsigned long long, unsigned long long, char const*, __va_list_tag*) + 108
4 libobjc.A.dylib 0x00007fff63c58526 _objc_fatal(char const*, ...) + 135
5 libobjc.A.dylib 0x00007fff63c62525 (anonymous namespace)::AutoreleasePoolPage::fastcheck(bool) + 125
6 libobjc.A.dylib 0x00007fff63c4a9f7 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 65
7 com.apple.CoreFoundation 0x00007fff37ab9ee6 _CFAutoreleasePoolPop + 22
8 com.apple.Foundation 0x00007fff39e66a5e -[NSAutoreleasePool drain] + 144
9 org.sfml-dev.sfml-window 0x000000010ffc86a5 drainThreadPool() + 37
10 org.sfml-dev.sfml-window 0x000000010ffc76e4 sf::priv::WindowImplCocoa::~WindowImplCocoa() + 148
11 org.sfml-dev.sfml-window 0x000000010ffc772f sf::priv::WindowImplCocoa::~WindowImplCocoa() + 15
12 org.sfml-dev.sfml-window 0x000000010ffb85ca sf::Window::~Window() + 58
13 org.wxwindows. 0x000000010fe8dc75 wxSfmlCanvas::~wxSfmlCanvas() + 37 (main.cpp:73)
14 org.wxwindows. 0x000000010fe8dc45 Canvas::~Canvas() + 21 (main.cpp:78)
15 org.wxwindows. 0x000000010fe8d505 Canvas::~Canvas() + 21 (main.cpp:78)
16 org.wxwindows. 0x000000010fe8d529 Canvas::~Canvas() + 25 (main.cpp:78)
17 org.wxwindows. 0x000000010fe8e740 AppFrame::~AppFrame() + 304 (memory:2285)
18 org.wxwindows. 0x000000010fe8b335 AppFrame::~AppFrame() + 21 (main.cpp:125)
19 org.wxwindows. 0x000000010fe8b359 AppFrame::~AppFrame() + 25 (main.cpp:125)
20 libwx_osx_cocoau-3.1.2.0.0.dylib 0x000000010fffdd3d wxAppConsoleBase::ProcessIdle() + 157
21 libwx_osx_cocoau-3.1.2.0.0.dylib 0x0000000110238476 wxAppBase::ProcessIdle() + 22
22 libwx_osx_cocoau-3.1.2.0.0.dylib 0x000000011018550a wxApp::ProcessIdle() + 26
23 libwx_osx_cocoau-3.1.2.0.0.dylib 0x00000001100e41fc wxCFEventLoop::OSXCommonModeObserverCallBack(__CFRunLoopObserver*, int, void*) + 92
24 com.apple.CoreFoundation 0x00007fff37b459cd __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
25 com.apple.CoreFoundation 0x00007fff37b45902 __CFRunLoopDoObservers + 452
26 com.apple.CoreFoundation 0x00007fff37ae7558 __CFRunLoopRun + 1469
27 com.apple.CoreFoundation 0x00007fff37ae6d48 CFRunLoopRunSpecific + 463
28 com.apple.HIToolbox 0x00007fff36d7dab5 RunCurrentEventLoopInMode + 293
29 com.apple.HIToolbox 0x00007fff36d7d7eb ReceiveNextEventCommon + 618
30 com.apple.HIToolbox 0x00007fff36d7d568 _BlockUntilNextEventMatchingListInModeWithFilter + 64
31 com.apple.AppKit 0x00007fff35038363 _DPSNextEvent + 997
32 com.apple.AppKit 0x00007fff35037102 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1362
33 com.apple.AppKit 0x00007fff35031165 -[NSApplication run] + 699
34 libwx_osx_cocoau-3.1.2.0.0.dylib 0x00000001101f0dff wxGUIEventLoop::OSXDoRun() + 207
35 libwx_osx_cocoau-3.1.2.0.0.dylib 0x00000001100e4ab1 wxCFEventLoop::DoRun() + 49
36 libwx_osx_cocoau-3.1.2.0.0.dylib 0x000000011002fcae wxEventLoopBase::Run() + 158
37 libwx_osx_cocoau-3.1.2.0.0.dylib 0x000000010fffda13 wxAppConsoleBase::MainLoop() + 99
38 libwx_osx_cocoau-3.1.2.0.0.dylib 0x000000011018555a wxApp::OnRun() + 26
39 libwx_osx_cocoau-3.1.2.0.0.dylib 0x0000000110067763 wxEntry(int&, wchar_t**) + 131
40 org.wxwindows. 0x000000010fe883b6 main + 38 (main.cpp:182)
41 libdyld.dylib 0x00007fff64d24ed9 start + 1
Thread 1:
0 libsystem_pthread.dylib 0x00007fff64f173f8 start_wqthread + 0
1 ??? 0x0000000054485244 0 + 1414025796
Thread 2:: Dispatch queue: NSCGSDisableUpdates
0 libsystem_kernel.dylib 0x00007fff64e5e17a mach_msg_trap + 10
1 libsystem_kernel.dylib 0x00007fff64e5e6d0 mach_msg + 60
2 com.apple.SkyLight 0x00007fff5dc44bc5 CGSUpdateManager::enable_updates_common() + 577
3 com.apple.SkyLight 0x00007fff5dbe7e3b CGSUpdateManager::enable_update(unsigned long long) + 317
4 libdispatch.dylib 0x00007fff64cd5d53 _dispatch_call_block_and_release + 12
5 libdispatch.dylib 0x00007fff64cd6dcf _dispatch_client_callout + 8
6 libdispatch.dylib 0x00007fff64cdd124 _dispatch_lane_serial_drain + 618
7 libdispatch.dylib 0x00007fff64cddbdc _dispatch_lane_invoke + 388
8 libdispatch.dylib 0x00007fff64ce6090 _dispatch_workloop_worker_thread + 603
9 libsystem_pthread.dylib 0x00007fff64f1760b _pthread_wqthread + 409
10 libsystem_pthread.dylib 0x00007fff64f17405 start_wqthread + 13
Thread 3:
0 libsystem_pthread.dylib 0x00007fff64f173f8 start_wqthread + 0
1 ??? 0x0000000054485244 0 + 1414025796
Thread 4:: com.apple.NSEventThread
0 libsystem_kernel.dylib 0x00007fff64e5e17a mach_msg_trap + 10
1 libsystem_kernel.dylib 0x00007fff64e5e6d0 mach_msg + 60
2 com.apple.CoreFoundation 0x00007fff37ae80c2 __CFRunLoopServiceMachPort + 337
3 com.apple.CoreFoundation 0x00007fff37ae7611 __CFRunLoopRun + 1654
4 com.apple.CoreFoundation 0x00007fff37ae6d48 CFRunLoopRunSpecific + 463
5 com.apple.AppKit 0x00007fff35040f89 _NSEventThread + 160
6 libsystem_pthread.dylib 0x00007fff64f18305 _pthread_body + 126
7 libsystem_pthread.dylib 0x00007fff64f1b26f _pthread_start + 70
8 libsystem_pthread.dylib 0x00007fff64f17415 thread_start + 13
Thread 5:
0 libsystem_pthread.dylib 0x00007fff64f173f8 start_wqthread + 0
Thread 0 crashed with X86 Thread State (64-bit):
rax: 0x0000000002000209 rbx: 0x0000000000000080 rcx: 0x00007ffedfd767c8 rdx: 0x0000000000000000
rdi: 0x0000000000000008 rsi: 0x0000000000000001 rbp: 0x00007ffedfd76810 rsp: 0x00007ffedfd767c8
r8: 0x00007febce519d50 r9: 0x0000000000000080 r10: 0x0000000000000000 r11: 0x0000000000000246
r12: 0x0000000000000000 r13: 0x0000000000000000 r14: 0x0000000000000001 r15: 0x0000000000000008
rip: 0x00007fff64e7c01e rfl: 0x0000000000000246 cr2: 0x0000000116681000
Logical CPU: 0
Error Code: 0x02000209
Trap Number: 133
I suspect wxControl and sf::RenderWindows are trying the close the NSView, which comes from the GetHandle() call, at the same time. Before I start dissecting through wxWidgets and SFML source with a debugger, I would like to ask if anyone here have a solution for gracefully handling this scenario.
Meanwhile, I will be actively debugging this issue while this forum post is active. If I find a solution first, I will most definitely update this post with the solution as reference for all who have or will encounter this issue in the future.
-James Harris