crash5band / MikuMikuWorld

Project Sekai score viewer and editor
MIT License
79 stars 62 forks source link

Unsupported language causes MMW fail to render (crash) #35

Closed GuanYixuan closed 1 year ago

GuanYixuan commented 1 year ago

Problem description: Running MMW leads to a white empty window, and soon after the window disappears (crashes) Platform: Windows 10

After half an hour of bug chasing in VS, I found the following chain. I think the problem is caused by unsupported languages and therefore there should be some "fallback" (for example use en as fallback) when user's system language is not supported.

When MMW starts, Application::update() in Application.cpp will be invoked, where a code block setting the localization exists:

(Application.cpp, in Application::update)
    if (config.language != language)
    {
        if (config.language == "auto")
        {
            // get system language
            std::string locale = Utilities::getSystemLocale();
            Localization::setLanguage(locale);
        }
        else
        {
            Localization::setLanguage(config.language);
        }

        language = config.language;
    }

If you just use the default setting (config.language == "auto") and your locale is supported (en or ja), then everything's fine. However, if your locale is not supported (for example fr), Localization::setLanguage fails silently, causing Localization::currentLanguage to be nullptr and therefore any call to getString will return empty string "":

(Localization.cpp)
    Language* Localization::currentLanguage = nullptr;

    ...

    bool Localization::setLanguage(const std::string& code)
    {
        auto it = Localization::languages.find(code);
        if (it == Localization::languages.end())
            return false;

        Localization::currentLanguage = it->second.get();
        return true;
    }

    ...

    const char* getString(const std::string& key)
    {
        if (!Localization::currentLanguage)
            return empty.c_str();

        return Localization::currentLanguage->getString(key);
    }

Finally, when MMW is trying to use the return value of getString to name widgets in ImGui, the empty string leads to duplicated name and duplicated hash, triggering an assertion in ImGui and crashing the program:

(imgui.cpp, in ImGui::ItemAdd)
        // [DEBUG] People keep stumbling on this problem and using "" as identifier in the root of a window instead of "##something".
        // Empty identifier are valid and useful in a small amount of cases, but 99.9% of the time you want to use "##something".
        // READ THE FAQ: https://dearimgui.com/faq
        IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!");

I hope it will be helpful for debugging and making MMW better :)

crash5band commented 1 year ago

Fixed with c885116 and ef71f1d