From 5cf2a958eba6cca2f0ec195fd04109dd43e4a187 Mon Sep 17 00:00:00 2001 From: Project579 Date: Sat, 24 Sep 2022 16:20:42 +0200 Subject: [PATCH] Make conversions between std::chrono time_point and string safer by not using "localtime" directly. --- apps/mwiniimporter/importer.cpp | 11 +++++------ apps/opencs/view/doc/view.cpp | 10 ++++------ apps/openmw/mwgui/savegamedialog.cpp | 5 +---- components/config/launchersettings.cpp | 24 +++++++++++++----------- components/debug/debugging.cpp | 8 +++++++- components/misc/timeconvert.hpp | 26 ++++++++++++++++++++++++-- 6 files changed, 54 insertions(+), 30 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 53d396a0cd..e00f0f0c1f 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -639,14 +639,13 @@ std::time_t MwIniImporter::lastWriteTime(const std::filesystem::path& filename, if (std::filesystem::exists(filename)) { std::filesystem::path resolved = std::filesystem::canonical(filename); - writeTime = Misc::to_time_t(std::filesystem::last_write_time(resolved)); + const auto time = std::filesystem::last_write_time(resolved); + writeTime = Misc::toTimeT(time); // print timestamp - const int size = 1024; - char timeStrBuffer[size]; - if (std::strftime(timeStrBuffer, size, "%x %X", localtime(&writeTime)) > 0) - std::cout << "content file: " << resolved << " timestamp = (" << writeTime << ") " << timeStrBuffer - << std::endl; + const auto str = Misc::fileTimeToString(time, "%x %X"); + if (!str.empty()) + std::cout << "content file: " << resolved << " timestamp = (" << writeTime << ") " << str << std::endl; } return writeTime; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 8987112dfe..7b68573665 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include "globaldebugprofilemenu.hpp" @@ -765,11 +766,7 @@ void CSVDoc::View::infoAbout() #endif // Get current year - time_t now = time(nullptr); - struct tm tstruct; - char copyrightInfo[40]; - tstruct = *localtime(&now); - strftime(copyrightInfo, sizeof(copyrightInfo), "Copyright © 2008-%Y OpenMW Team", &tstruct); + const auto copyrightInfo = Misc::timeToString(std::chrono::system_clock::now(), "Copyright © 2008-%Y OpenMW Team"); QString aboutText = QString( "

" @@ -788,7 +785,8 @@ void CSVDoc::View::infoAbout() .arg(versionInfo, tr("OpenMW-CS is a content file editor for OpenMW, a modern, free and open source game " "engine."), - tr(copyrightInfo), tr("Home Page:"), tr("Forum:"), tr("Bug Tracker:"), tr("IRC:")); + tr(copyrightInfo.c_str()), tr("Home Page:"), tr("Forum:"), tr("Bug Tracker:"), + tr("IRC:")); QMessageBox::about(this, "About OpenMW-CS", aboutText); } diff --git a/apps/openmw/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index c2bfbf682e..462fab75e0 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -410,11 +410,8 @@ namespace MWGui throw std::runtime_error("Can't find selected slot"); std::stringstream text; - time_t time = Misc::to_time_t(mCurrentSlot->mTimeStamp); - struct tm* timeinfo; - timeinfo = localtime(&time); - text << std::put_time(timeinfo, "%Y.%m.%d %T") << "\n"; + text << Misc::fileTimeToString(mCurrentSlot->mTimeStamp, "%Y.%m.%d %T") << "\n"; text << "#{sLevel} " << mCurrentSlot->mProfile.mPlayerLevel << "\n"; text << "#{sCell=" << mCurrentSlot->mProfile.mPlayerCell << "}\n"; diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index f56cbc93e3..743ff56c3a 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -223,18 +223,20 @@ bool Config::LauncherSettings::isEqual(const QStringList& list1, const QStringLi QString Config::LauncherSettings::makeNewContentListName() { // basically, use date and time as the name e.g. YYYY-MM-DDThh:mm:ss - time_t rawtime; - struct tm* timeinfo; - - time(&rawtime); - timeinfo = localtime(&rawtime); + auto rawtime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + tm timeinfo{}; +#ifdef _WIN32 + (void)localtime_s(&timeinfo, &rawtime); +#else + (void)localtime_r(&rawtime, &timeinfo); +#endif int base = 10; QChar zeroPad('0'); return QString("%1-%2-%3T%4:%5:%6") - .arg(timeinfo->tm_year + 1900, 4) - .arg(timeinfo->tm_mon + 1, 2, base, zeroPad) - .arg(timeinfo->tm_mday, 2, base, zeroPad) - .arg(timeinfo->tm_hour, 2, base, zeroPad) - .arg(timeinfo->tm_min, 2, base, zeroPad) - .arg(timeinfo->tm_sec, 2, base, zeroPad); + .arg(timeinfo.tm_year + 1900, 4) + .arg(timeinfo.tm_mon + 1, 2, base, zeroPad) + .arg(timeinfo.tm_mday, 2, base, zeroPad) + .arg(timeinfo.tm_hour, 2, base, zeroPad) + .arg(timeinfo.tm_min, 2, base, zeroPad) + .arg(timeinfo.tm_sec, 2, base, zeroPad); } diff --git a/components/debug/debugging.cpp b/components/debug/debugging.cpp index a86e390d0a..017d73a177 100644 --- a/components/debug/debugging.cpp +++ b/components/debug/debugging.cpp @@ -99,7 +99,13 @@ namespace Debug prefix[0] = '['; const auto now = std::chrono::system_clock::now(); const auto time = std::chrono::system_clock::to_time_t(now); - prefixSize = std::strftime(prefix + 1, sizeof(prefix) - 1, "%T", std::localtime(&time)) + 1; + tm time_info{}; +#ifdef _WIN32 + (void)localtime_s(&time_info, &time); +#else + (void)localtime_r(&time, &time_info); +#endif + prefixSize = std::strftime(prefix + 1, sizeof(prefix) - 1, "%T", &time_info) + 1; char levelLetter = " EWIVD*"[int(level)]; const auto ms = std::chrono::duration_cast(now.time_since_epoch()).count(); prefixSize += snprintf(prefix + prefixSize, sizeof(prefix) - prefixSize, ".%03u %c] ", diff --git a/components/misc/timeconvert.hpp b/components/misc/timeconvert.hpp index 1f4c8e9bc6..3c1459d91d 100644 --- a/components/misc/timeconvert.hpp +++ b/components/misc/timeconvert.hpp @@ -2,17 +2,39 @@ #define OPENMW_COMPONENTS_MISC_TIMECONVERT_H #include -#include namespace Misc { template - inline std::time_t to_time_t(TP tp) + inline std::time_t toTimeT(TP tp) { using namespace std::chrono; auto sctp = time_point_cast(tp - TP::clock::now() + system_clock::now()); return system_clock::to_time_t(sctp); } + + inline std::string timeTToString(const std::time_t tp, const char* fmt) + { + tm time_info{}; +#ifdef _WIN32 + (void)localtime_s(&time_info, &tp); +#else + (void)localtime_r(&tp, &time_info); +#endif + std::stringstream out; + out << std::put_time(&time_info, fmt); + return out.str(); + } + + inline std::string fileTimeToString(const std::filesystem::file_time_type& tp, const char* fmt) + { + return timeTToString(toTimeT(tp), fmt); + } + + inline std::string timeToString(const std::chrono::system_clock::time_point& tp, const char* fmt) + { + return timeTToString(std::chrono::system_clock::to_time_t(tp), fmt); + } } // namespace Misc #endif