Skip to content

Hidden Error: Memory access violation in options menu during localization reload #367

@ProfLander

Description

@ProfLander

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>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions