-
Notifications
You must be signed in to change notification settings - Fork 124
Description
When the language is changed via the options menu, the localization reload function causes the main menu to be xr_delete'd and replaced with a fresh copy before option callbacks have finished running.
As the UIOptions Lua class accesses self.owner - a main menu reference populated at construction time - this causes MAVs when the resulting pointer is accessed in post-callback logic, which are hidden by luabind's SEH-empowered exception handler under MSVC.
There are two distinct variants of MAV, one involving access to self.owner's child CUIMMShniaga, and the other to self.owner itself. Which occurs is inconsistent, though Crash 1 can be caused consistently by inspecting deep into the call stack with the debugger. A non-debugged build appears to pick randomly between it and Crash 2, potentially implicating GC as cause of the variation.
Curated call stack:
<Main Menu>
<Options>
<Change Language>
<Apply>
// Button handler
CUI3tButton::OnClick()
// Dispatch to lua
CUIDialogWndEx::SendMessage(CUIWindow* pWnd, s16 msg, void* pData)
// Options accept handler
ui_options.UIOptions:On_Accept()
// Localization update functor
ui_options.func_localization()
// Script loctable reload
game.reload_language()
// Loctable reload
CStringTable::ReloadLanguage()
// Hide main menu
CMainMenu::Activate(false)
// Show main menu
CMainMenu::Activate(true)
// Reinstantiate start dialog
CMainMenu::ReloadUI()
// Construct new start dialog
NEW_INSTANCE(TEXT2CLSID("MAIN_MNU"))
// Lua constructor, sets `owner` on options menu
ui_main_menu.main_menu:__init()
// Build controls
ui_main_menu.main_menu:InitControls()
// Initialize shniaga + magnifier
CScriptXmlInit::InitMMShniaga("shniaga_wnd",self)
// Delete old main menu
xr_delete(m_startDialog)
// Accept handler forwards to cancel handler
UIOptions:On_Cancel()
// Attempt to show the main menu this options menu was constructed with
// (The `m_startDialog` that was `xr_delete`'d above)
self.owner:ShowDialog(true)
// Dialog window show handler
CUIDialogWnd::ShowDialog
// Dialog holder start
CDialogHolder::StartDialog
<Crash 1 - access violation, self.owner has been deleted>
// Attempt to hide this options menu (child of `m_startDialog`)
self:HideDialog()
// Attempt to call the main menu's lua-level show function
self.owner:Show(true)
// Lua show function tries to show the magnifier
ui_main_menu.main_menu:Show()
// C++ handler
CUIMMShniaga::SetVisibleMagnifier(true)
<Crash 2 - access violation, self has been deleted>