Error handling for corrupt .mo files (#6215)

Previously, a corrupt .mo file caused the game to exit immediately. This meant
that a broken add-on could stop the user from reaching the main menu, a
situation that could only be recovered by editing the preferences file or by
deleting the add-on with a file browser.

The engine generates the locale 3 times:
* once with no .mo files loaded
* once with only the mainline .mo files loaded
* once with all .mo files loaded

This means that:
* starting Wesnoth with a corrupt .mo file in mainline will make the engine run
  showing en_US text
* changing language with a corrupt .mo file in mainline will make the engine
  stay in whatever language it had successfully loaded
* a corrupt .mo file in an add-on will disable .mo files in all add-ons, but
  leave mainline translations active, and will let the user play the game
This commit is contained in:
Steve Cotton 2021-10-21 20:27:06 +02:00 committed by GitHub
parent 19da178e68
commit 9e216c7ea8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 0 deletions

View file

@ -41,6 +41,7 @@
* AI: fixed custom synced commands not changing the game state
* Messenger MAI: fixed bug of own units sometimes blocking the path to a waypoint for the messenger
* Correct unit display adjustments on certain tiles when at zoom level other than 100% (issue #5974)
* Fix the engine exiting immediately due to a corrupt .mo file (issue #6194)
## Version 1.15.14
### Add-ons client

View file

@ -293,6 +293,19 @@ namespace
is_dirty_ = true;
}
/* This is called three times: once during the constructor, before any .mo files' paths have
* been added to the generator, once after adding the mainline .mo files, and once more
* after adding all add-ons. Corrupt .mo files might make the called functions throw, and so
* this might fail as soon as we've added message paths.
*
* Throwing exceptions from here is (in 1.15.18) going to end up in wesnoth.cpp's "Caught
* general ... exception" handler, so the effect of letting an exception escape this
* function is an immediate exit. Given that, it doesn't seem useful to change the assert
* to a throw, at least not within the 1.16 branch.
*
* Postcondition: current_locale_ is a valid boost-generated locale, supplying the bl::info
* facet. If there are corrupt .mo files, the locale might have no translations loaded.
*/
void update_locale_internal()
{
try
@ -320,6 +333,18 @@ namespace
<< "' variant='" << info.variant()
<< "'" << std::endl;
}
catch(const std::runtime_error&)
{
assert(std::has_facet<bl::info>(current_locale_));
const bl::info& info = std::use_facet<bl::info>(current_locale_);
ERR_G << "Failed to update locale due to runtime error, locale is now: "
<< "name='" << info.name()
<< "' country='" << info.country()
<< "' language='" << info.language()
<< "' encoding='" << info.encoding()
<< "' variant='" << info.variant()
<< "'" << std::endl;
}
is_dirty_ = false;
}