Skip to content
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

[BUG] macOS: a crash report pop-up appears on exiting the app #680

Closed
jonathanperret opened this issue Jul 24, 2024 · 1 comment
Closed

Comments

@jonathanperret
Copy link
Contributor

Environment
AYAB software version: 1.0.0-dev
Computer/OS: macOS 14.2 on M1

Describe the bug

The AYAB app causes a crash report window ("AYAB quit unexpectedly") to pop up after quitting.

To Reproduce
Steps to reproduce the behavior:

  1. Launch a recent build of AYAB, for example https://github.com/AllYarnsAreBeautiful/ayab-desktop/releases/tag/v1.0.0-test-knit-display
    ⚠️ Please check an actual build as downloaded from GitHub or produced locally with fbs freeze, not running from source with fbs run.
    ⚠️ Launch the app by double-clicking its icon in the Finder; I've noticed that running it from a terminal can suppress the crash report pop-up (in particular, launching from the Visual Studio Code terminal disables the crash report window for me).
  2. Quit the app by doing one of the following (when testing that the bug is fixed, please try each of these at least once):
    • Selecting the Quit item from the File menu in the AYAB window
    • Select the Quit item from the AYAB menu in the macOS menu bar
    • Pressing the Cmd+Q shortcut while AYAB is the active application
    • Right-clicking or Ctrl-clicking the AYAB icon in the Dock and selecting the "Quit" menu item
    • Closing the main AYAB window by clicking the red close button in the top-left corner
  3. Potentially wait a few seconds while macOS collects the crash report information.
  4. See a macOS crash report window pop up:
AYAB-crash-report

If you don't see a crash report window, please check the following before marking the bug as fixed:

  • Make sure you don't have an existing crash report window open in the background, as macOS will not open a second crash report window for the same app while one is already open. This is made tricky by the fact that this window does not have an associated icon on the Dock. It does appear on Mission Control/Exposé though, just make sure it is not open on another desktop or screen.
  • It sems that sometimes macOS decides that you've seen enough of these crash report windows and stops showing them. Clearing the ~/Library/Logs/DiagnosticReports folder where the crash reports are stored may help, or rebooting. When in doubt, I found it helps to keep a known-affected build of AYAB around so that you can run it and check that the crash report window still appears.

Expected behavior
No crash report window should pop up when exiting the app.

Additional context

This is more or less a re-opening of #640 , which I thought I had fixed with #670 but evidently my testing was not thorough enough, hence the detailed testing instructions above.

Here is the beginning of one crash report seen with the build referenced above.

-------------------------------------
Translated Report (Full Report Below)
-------------------------------------

Process:               AYAB-mac [41298]
Path:                  /Users/USER/Downloads/AYAB-v1.0.0-test-knit-display.app/Contents/MacOS/AYAB-mac
Identifier:            
Version:               1.0.0 (1.0.0)
Code Type:             ARM-64 (Native)
Parent Process:        launchd [1]
User ID:               501

Date/Time:             2024-07-24 11:28:28.1529 +0200
OS Version:            macOS 14.2 (23C64)
Report Version:        12
Anonymous UUID:        51F69B52-7370-B01D-AB5E-3E7850A84813

Sleep/Wake UUID:       5AA754B1-B46A-4B7F-8B9A-8571C3168237

Time Awake Since Boot: 380000 seconds
Time Since Wake:       2078 seconds

System Integrity Protection: enabled

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_CRASH (SIGABRT)
Exception Codes:       0x0000000000000000, 0x0000000000000000

Termination Reason:    Namespace SIGNAL, Code 6 Abort trap: 6
Terminating Process:   AYAB-mac [41298]

Application Specific Information:
abort() called


Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	       0x180d5e0dc __pthread_kill + 8
1   libsystem_pthread.dylib       	       0x180d95cc0 pthread_kill + 288
2   libsystem_c.dylib             	       0x180ca1a40 abort + 180
3   QtCore                        	       0x126b77ba8 qAbort() + 12
4   QtCore                        	       0x126b7f2c8 0x126b60000 + 127688
5   QtCore                        	       0x126b7ad24 0x126b60000 + 109860
6   QtCore                        	       0x126e6b0bc QMessageLogger::fatal(char const*, ...) const + 32
7   QtCore                        	       0x126e70c68 0x126b60000 + 3214440
8   QtCore                        	       0x126cc1304 QThread::~QThread() + 256
9   QtCore.abi3.so                	       0x126064d64 QThreadWrapper::~QThreadWrapper() + 56
10  QtCore                        	       0x126c23200 QObjectPrivate::deleteChildren() + 152
11  QtWidgets                     	       0x135b02b84 QWidget::~QWidget() + 1172
12  QtWidgets.abi3.so             	       0x136690f48 QMainWindowWrapper::~QMainWindowWrapper() + 64
13  libpyside6.abi3.6.6.dylib     	       0x1067fdf48 PySide::destructionVisitor(SbkObject*, void*) + 136
14  libshiboken6.abi3.6.6.dylib   	       0x1043f4118 Shiboken::BindingManager::visitAllPyObjects(void (*)(SbkObject*, void*), void*) + 132
15  libpyside6.abi3.6.6.dylib     	       0x1067fde54 PySide::destroyQCoreApplication() + 116
16  libpyside6.abi3.6.6.dylib     	       0x1067fddb0 PySide::runCleanupFunctions() + 100
17  QtCore.abi3.so                	       0x1260462a4 SbkQtCoreModule___moduleShutdown(_object*) + 36
18  Python                        	       0x103be86b0 cfunction_vectorcall_NOARGS + 88
19  Python                        	       0x103d4791c atexit_callfuncs + 492
20  Python                        	       0x103d12cbc Py_FinalizeEx + 104
21  Python                        	       0x103d15f54 Py_Exit + 20
22  Python                        	       0x103d1ba0c handle_system_exit + 44
23  Python                        	       0x103d199b4 _PyErr_PrintEx + 60
24  AYAB-mac                      	       0x1021787e4 0x102174000 + 18404
25  AYAB-mac                      	       0x102178ae8 0x102174000 + 19176
26  dyld                          	       0x180a150e0 start + 2360
jonathanperret added a commit to jonathanperret/ayab-desktop that referenced this issue Jul 24, 2024
The current code spawns a dedicated thread to handle playing sound effects.

This is unnecessary as the `simpleaudio` API already is non-blocking, i.e. calling `wave_obj.play()`
returns immediately while the sound plays in the background (see https://simpleaudio.readthedocs.io/en/latest/capabilities.html#asynchronous-interface). At the worst,
loading the sound file, which is synchronous, could block the calling thread for a few milliseconds
but that happens only once and is unlikely to be an issue.

The `AudioWorker.play` method does have a `blocking` argument that is supposed to support
blocking the caller until the sound has finished playing, but this is never used in the current codebase.

But more conclusively, it turns out that due to an oversight, practically no code currently executes
on the audio player thread. The `AudioWorker` object is assigned to a new thread, but because the
`AudioPlayer.play` method calls `__worker.play` without going through a signal, the `AudioWorker.play`
method actually executes on the thread that called `AudioPlayer.play`. In practice this is the UI thread,
because `audio.play` is called through a signal on `SignalReceiver`, which lives on that thread. Thus,
the time-sensitive engine thread is already isolated from any slowness in reading or playing audio.

This commit reduces the `AudioPlayer` class to a plain Python object whose only responsibilities
are to load and play the application's sound effects. It also simplifies the file loading logic by
removing the direct call to the `wave` library in favor of the `from_wave_file` helper method
offered by `simpleaudio`, which in practice uses the exact same call to the `wave` library.

A notable benefit of removing this thread is that the application no longer crashes with an `abort`
call upon exit (issue AllYarnsAreBeautiful#680), caused by improper termination of the audio thread.
dl1com pushed a commit that referenced this issue Jul 25, 2024
The current code spawns a dedicated thread to handle playing sound effects.

This is unnecessary as the `simpleaudio` API already is non-blocking, i.e. calling `wave_obj.play()`
returns immediately while the sound plays in the background (see https://simpleaudio.readthedocs.io/en/latest/capabilities.html#asynchronous-interface). At the worst,
loading the sound file, which is synchronous, could block the calling thread for a few milliseconds
but that happens only once and is unlikely to be an issue.

The `AudioWorker.play` method does have a `blocking` argument that is supposed to support
blocking the caller until the sound has finished playing, but this is never used in the current codebase.

But more conclusively, it turns out that due to an oversight, practically no code currently executes
on the audio player thread. The `AudioWorker` object is assigned to a new thread, but because the
`AudioPlayer.play` method calls `__worker.play` without going through a signal, the `AudioWorker.play`
method actually executes on the thread that called `AudioPlayer.play`. In practice this is the UI thread,
because `audio.play` is called through a signal on `SignalReceiver`, which lives on that thread. Thus,
the time-sensitive engine thread is already isolated from any slowness in reading or playing audio.

This commit reduces the `AudioPlayer` class to a plain Python object whose only responsibilities
are to load and play the application's sound effects. It also simplifies the file loading logic by
removing the direct call to the `wave` library in favor of the `from_wave_file` helper method
offered by `simpleaudio`, which in practice uses the exact same call to the `wave` library.

A notable benefit of removing this thread is that the application no longer crashes with an `abort`
call upon exit (issue #680), caused by improper termination of the audio thread.
@X-sam
Copy link
Member

X-sam commented Jul 29, 2024

Addressed in #681

@X-sam X-sam closed this as completed Jul 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants