fix: use reentrant localtime_r/localtime_s off the worker thread

std::localtime shares a process-wide static tm; both sites are reachable from background threads (the RPC price-parse on the worker thread, and Logger::write from worker/monitor threads), so a concurrent localtime call could clobber the struct between the call and the read. Copy into a local std::tm via localtime_r / localtime_s, matching the codebase's existing convention (console_tab rpcTraceTimestamp, app_network, etc.). From the console-tab audit; benign (garbled/stale timestamp only), no crash or state impact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-18 18:03:10 -05:00
parent 7d47c6e14e
commit 82d3178119
2 changed files with 18 additions and 3 deletions

View File

@@ -434,8 +434,15 @@ std::optional<NetworkRefreshService::PriceRefreshResult> NetworkRefreshService::
result.market.market_cap = data.value("usd_market_cap", 0.0);
char buf[64];
std::tm* tm = std::localtime(&fetchedAt);
if (tm && std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm) > 0) {
// Runs on the RPC worker thread — std::localtime shares a process-wide static tm, so use the
// reentrant variant into a local tm (matches the rest of the codebase).
std::tm tmv{};
#ifdef _WIN32
localtime_s(&tmv, &fetchedAt);
#else
localtime_r(&fetchedAt, &tmv);
#endif
if (std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tmv) > 0) {
result.market.last_updated = buf;
}
return result;

View File

@@ -57,7 +57,15 @@ void Logger::write(const std::string& message)
now.time_since_epoch()) % 1000;
std::stringstream ss;
ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S");
// Reachable from worker/monitor threads — std::localtime shares a process-wide static tm, so use the
// reentrant variant into a local tm (the logger's own mutex can't protect other localtime callers).
std::tm tmv{};
#ifdef _WIN32
localtime_s(&tmv, &time);
#else
localtime_r(&time, &tmv);
#endif
ss << std::put_time(&tmv, "%Y-%m-%d %H:%M:%S");
ss << '.' << std::setfill('0') << std::setw(3) << ms.count();
ss << " | " << message;