Repository navigation
Conversation
… destroyed Closing the game properties dialog crashed whenever the game has a Tweaks tab and isn't running. tweaks_tab is the last member, so it is destroyed first; deleting the remaining tab pages then makes the tab widget emit currentChanged, finally with index -1. widget(-1) is null, which matched the now-null tweaks_tab, so the handler ran ApplySettingTabs() on deleted tabs and RefreshRecommendations() on a null tab. Block the tab widget's signals in the destructor and check the index and the tab in the handler. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YQZoXmAUTth3PtUD1X3sFH
|
Can't reproduce this behavior on linux with my local build. |
|
Turns out I couldn't reproduce it because I tested a CMAKE_BUILD_TYPE=Release build with Qt 6.12, where the handler happens to no-op. The mechanism checks out. tweaks_tab is the last member, so its page leaves the stack first, and QTabWidget emits currentChanged(-1) while the rest of the dialog is unwinding. Atthat point ui->widget(-1) is null and tweaks_tab.get() reads as null as well under the reporter's codegen, so the handler runs ApplySettingTabs() over tab_group, whose Tab objects arealready destroyed. Reading the destroyed unique_ptr is UB, which is why it reproduces in some builds and not others: a standalone harness with the same object layout segfaults underGCC at -O0 and survives at -O2. |
|
Same shape is still live in configure_dialog.cpp:107: debug_tab_tab is destroyed before cpu_tab, audio_tab and applets_tab, so closing Settings with one of those selected callsSetCurrentIndex(0) on freed memory. ~ConfigureDialog should be fixed in the same ways as well. |
Same shape as the per-game dialog: debug_tab_tab is destroyed before cpu_tab, audio_tab and applets_tab, so deleting those pages makes the tab widget emit currentChanged and the handler calls debug_tab_tab->SetCurrentIndex(0) on a destroyed tab. Closing Settings with one of them selected reads freed memory. Block the tab widget's signals in ~ConfigureDialog as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YQZoXnswrY92GrEdS2FRo5
|
Added the same fix for ~ConfigureDialog in e9235f6: it blocks the tab widget's signals before the tabs are destroyed, so the currentChanged handler can't reach the already-destroyed debug_tab_tab when settings closes with CPU, Audio or Applets selected. |
Summary
Since the per-game Tweaks tab (df62e5f), closing a game's Properties dialog with OK crashes the emulator (access violation) for any game that has a Tweaks tab, when no game is running. Hyrule Warriors: Age of Imprisonment has one for its frame-rate options.
Cause.
tweaks_tabis the last member ofConfigurePerGame, so it is destroyed first. Deleting the remaining tab pages then makes the tab widget emitcurrentChanged, finally with index -1.widget(-1)is null, which matches the now-nulltweaks_tab, so the handler runsApplySettingTabs()on tabs that are already deleted andRefreshRecommendations()on a null tab. Three crash dumps from the daily build fault in exactly those two places (mov rcx, [rcx+0x48]withrcx = 0inRefreshRecommendations, and a null read insideApplySettingTabs), both under the dialog's teardown afterOnGameListOpenPerGameProperties.Fix (
yuzu/configuration/configure_per_game.cpp): block the tab widget's signals in the destructor, and check the index and the tab in the handler.Type of change
Related issues
None
Testing
Tested: Hyrule Warriors: Age of Imprisonment, Properties -> change a setting -> OK: crashed every time on daily-20261112, no crash with this change.
Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_01YQZoXmAUTth3PtUD1X3sFH
Summary by CodeRabbit