Fixed crash on startup on Windows in paths with spaces

If OMP_WAIT_POLICY is not set, the game relaunches itself using
_execv() after setting the environment variable. It passes the entire
argv array as argv for the new launch, including argv[0] (program
path). If the program path contains spaces and is not surrounded in
quotes, Windows splits the path on quotes and creates a separate
parameter for each part (e.g.
"I:\Battle for Wesnoth\wesnoth\wesnoth.exe" becomes {"I:\Battle",
"for", "Wesnoth\wesnoth\wesnoth.exe"}). Boost::program_options
interprets the last two as positional parameters (the first one is
skipped, as the game expects the first parameter to store the program
path) and crashes the game because only one positional parameter is
allowed.

Fixed by quoting the path in the argv array.
This commit is contained in:
Jyrki Vesterinen 2016-01-01 08:14:45 +02:00
parent 0f8998d121
commit 97952b0d48
2 changed files with 43 additions and 25 deletions

View file

@ -240,6 +240,12 @@ std::string &strip(std::string &str);
/** Remove whitespace from the back of the string 'str'. */
std::string &strip_end(std::string &str);
/** Surround the string 'str' with double quotes. */
inline std::string quote(const std::string &str)
{
return '"' + str + '"';
}
/** Convert no, false, off, 0, 0.0 to false, empty to def, and others to true */
bool string_bool(const std::string& str,bool def=false);

View file

@ -49,6 +49,7 @@
#include "serialization/binary_or_text.hpp" // for config_writer
#include "serialization/parser.hpp" // for read
#include "serialization/preprocessor.hpp" // for preproc_define, etc
#include "serialization/string_utils.hpp"
#include "serialization/validator.hpp" // for strict_validation_enabled
#include "serialization/unicode_cast.hpp"
#include "sound.hpp" // for commit_music_changes, etc
@ -71,6 +72,7 @@
#endif // _MSC_VER
#include <SDL.h> // for SDL_Init, SDL_INIT_TIMER
#include <boost/bind.hpp>
#include <boost/foreach.hpp> // for auto_any_base, etc
#include <boost/iostreams/categories.hpp> // for input, output
#include <boost/iostreams/copy.hpp> // for copy
@ -82,6 +84,7 @@
#include <boost/scoped_ptr.hpp> // for scoped_ptr
#include <boost/tuple/tuple.hpp> // for tuple
#include <algorithm> // for transform
#include <cerrno> // for ENOMEM
#include <clocale> // for setlocale, NULL, LC_ALL, etc
#include <cstdio> // for remove, fprintf, stderr
@ -90,6 +93,7 @@
#include <exception> // for exception
#include <fstream> // for operator<<, basic_ostream, etc
#include <iostream> // for cerr, cout
#include <vector>
//#define NO_CATCH_AT_GAME_END
@ -934,31 +938,6 @@ int main(int argc, char** argv)
VLDEnable();
#endif
#ifdef _OPENMP
// Wesnoth is a special case for OMP
// OMP wait strategy is to have threads busy-loop for 100ms
// if there is nothing to do, they then go to sleep.
// this avoids the scheduler putting the thread to sleep when work
// is about to be available
//
// However Wesnoth has a lot of very small jobs that need to be done
// at each redraw => 50fps every 2ms.
// All the threads are thus busy-waiting all the time, hogging the CPU
// To avoid that problem, we need to set the OMP_WAIT_POLICY env var
// but that var is read by OMP at library loading time (before main)
// thus the relaunching of ourselves after setting the variable.
#if !defined(_WIN32) && !defined(__APPLE__)
if (!getenv("OMP_WAIT_POLICY")) {
setenv("OMP_WAIT_POLICY", "PASSIVE", 1);
execv(argv[0], argv);
}
#elif _MSC_VER >= 1600
if (!getenv("OMP_WAIT_POLICY")) {
_putenv_s("OMP_WAIT_POLICY", "PASSIVE");
_execv(argv[0], argv);
}
#endif
#endif //_OPENMP
#ifdef _WIN32
(void)argc;
(void)argv;
@ -986,6 +965,39 @@ int main(int argc, char** argv)
}
#endif
assert(!args.empty());
#ifdef _OPENMP
// Wesnoth is a special case for OMP
// OMP wait strategy is to have threads busy-loop for 100ms
// if there is nothing to do, they then go to sleep.
// this avoids the scheduler putting the thread to sleep when work
// is about to be available
//
// However Wesnoth has a lot of very small jobs that need to be done
// at each redraw => 50fps every 2ms.
// All the threads are thus busy-waiting all the time, hogging the CPU
// To avoid that problem, we need to set the OMP_WAIT_POLICY env var
// but that var is read by OMP at library loading time (before main)
// thus the relaunching of ourselves after setting the variable.
#if !defined(_WIN32) && !defined(__APPLE__)
if (!getenv("OMP_WAIT_POLICY")) {
setenv("OMP_WAIT_POLICY", "PASSIVE", 1);
execv(argv[0], argv);
}
#elif _MSC_VER >= 1600
if (!getenv("OMP_WAIT_POLICY")) {
_putenv_s("OMP_WAIT_POLICY", "PASSIVE");
args[0] = utils::quote(args[0]);
// NewArgs contains one more element than args in order to be
// NULL terminated (its buffer will be passed to _execv() as argv).
std::vector<const char*> newArgs(args.size() + 1, NULL);
std::transform(args.begin(), args.end(),
newArgs.begin(), boost::bind(&std::string::c_str, _1));
_execv(argv[0], &newArgs[0]);
}
#endif
#endif //_OPENMP
if(SDL_Init(SDL_INIT_TIMER) < 0) {
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
return(1);