diff --git a/application/application.cpp b/application/application.cpp index f5bec7cf..a6b88ae8 100644 --- a/application/application.cpp +++ b/application/application.cpp @@ -31,6 +31,7 @@ http://mozilla.org/MPL/2.0/. #include "utilities/dictionary.h" #include "version_info.h" #include +#include #include "utilities/translation.h" #if WITH_DISCORD_RPC @@ -320,9 +321,11 @@ int eu07_application::init(int Argc, char *Argv[]) return result; } - // the run's seed, settled once and kept in Globals: the engines come out of it + // the run's seed, settled once and kept in Globals: the engines come out of it. + // narrowed on purpose - mt19937 and seed_of() both work on 32 bits, and that is + // the seed somebody can write down and pass on if (!Global.random_seed) - Global.random_seed = true_random_seed(); + Global.random_seed = static_cast(true_random_seed()); Global.random_engine.seed(Global.random_seed); Global.local_random_engine.seed(Global.random_seed); @@ -1149,7 +1152,7 @@ int eu07_application::init_settings(int Argc, char *Argv[]) if (i + 1 < Argc) { Global.random_seed = seed_of(Argv[++i]); - WriteLog("seed given on the command line: " + std::string(Argv[i]) + " -> " + std::to_string(Global.random_seed)); + WriteLog(std::format("seed given on the command line: {} -> {}", Argv[i], Global.random_seed)); } } else @@ -1434,7 +1437,7 @@ int eu07_application::init_data() int eu07_application::init_modes() { - Global.local_random_engine.seed(true_random_seed()); + Global.local_random_engine.seed(static_cast(true_random_seed())); if ((!Global.network_servers.empty() || Global.network_client) && Global.SceneryFile.empty()) { diff --git a/utilities/utilities.cpp b/utilities/utilities.cpp index 5ff79092..c1d0b73d 100644 --- a/utilities/utilities.cpp +++ b/utilities/utilities.cpp @@ -29,6 +29,7 @@ Copyright (C) 2007-2014 Maciej Cierniak #include "utilities/Globals.h" #include "utilities/parser.h" #include "utilities/U8.h" +#include "utilities/Logs.h" @@ -142,21 +143,28 @@ std::uint64_t true_random_seed() try { std::random_device rd; - if (rd.entropy() > 0.0) + if (rd.entropy() > 0.0) { - std::uint32_t high = rd(); - std::uint32_t low = rd(); + // NOTE: both halves have to be 64 bit wide before the shift - shifting a std::uint32_t + // by 32 is undefined behaviour, and drops the high half of the seed + std::uint64_t const high{rd()}; + std::uint64_t const low{rd()}; return (high << 32) | low; } } - catch (...) {} + catch (std::exception const &Error) + { + // std::random_device throws when the machine has no usable hardware entropy source; + // the clock below stands in for it, which is worth saying out loud since it is a + // weaker seed than the caller asked for + WriteLog(std::format("random: no hardware entropy source ({}), seeding from the clock instead", Error.what())); + } return static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()); } std::uint32_t seed_of(std::string const &Text) { - std::uint32_t number{}; - if (std::from_chars(Text.data(), Text.data() + Text.size(), number).ec == std::errc{}) + if (std::uint32_t number{}; std::from_chars(Text.data(), Text.data() + Text.size(), number).ec == std::errc{}) { return number; }