Skip to content

Commit 82e2e37

Browse files
committed
Harden Win10 GUI startup logging path
1 parent afea932 commit 82e2e37

File tree

2 files changed

+77
-12
lines changed

2 files changed

+77
-12
lines changed

include/ultra/logging.hpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
33
#include <cstdio>
44
#include <cstdarg>
55
#include <chrono>
6-
#include <mutex>
76
#ifdef _WIN32
7+
#ifndef NOMINMAX
8+
#define NOMINMAX
9+
#endif
810
#include <io.h>
11+
#include <windows.h>
12+
#else
13+
#include <mutex>
914
#endif
1015

1116
// Windows headers define ERROR as a macro - undefine it
@@ -20,7 +25,11 @@ inline auto g_log_start_time = std::chrono::steady_clock::now();
2025

2126
// Log output file (nullptr = stderr)
2227
inline FILE* g_log_file = nullptr;
28+
#ifdef _WIN32
29+
inline SRWLOCK g_log_lock = SRWLOCK_INIT;
30+
#else
2331
inline std::mutex g_log_mutex;
32+
#endif
2433

2534
// Thread-local station tag for multi-station debug (e.g. "ALPHA" or "BRAVO")
2635
inline thread_local const char* g_log_station_tag = nullptr;
@@ -63,23 +72,27 @@ inline void setLogLevel(LogLevel level) {
6372

6473
// Set log output file (call with nullptr to use stderr)
6574
inline void setLogFile(FILE* file) {
75+
#ifdef _WIN32
76+
AcquireSRWLockExclusive(&g_log_lock);
77+
g_log_file = file;
78+
ReleaseSRWLockExclusive(&g_log_lock);
79+
#else
6680
std::lock_guard<std::mutex> lock(g_log_mutex);
6781
g_log_file = file;
82+
#endif
6883
}
6984

7085
// Core logging function
7186
inline void log(LogLevel level, const char* category, const char* format, ...) {
7287
if (level > g_log_level) return;
7388

7489
#ifdef _WIN32
75-
// During early GUI startup on some Win10 systems, touching the shared
76-
// logging mutex/CRT stream path can crash. If no explicit file sink is set,
77-
// skip logging entirely.
78-
FILE* out = g_log_file;
90+
AcquireSRWLockShared(&g_log_lock);
91+
FILE* out = g_log_file; // No stderr fallback on GUI subsystem builds.
7992
if (!out) {
93+
ReleaseSRWLockShared(&g_log_lock);
8094
return;
8195
}
82-
std::lock_guard<std::mutex> lock(g_log_mutex);
8396
#else
8497
std::lock_guard<std::mutex> lock(g_log_mutex);
8598
FILE* out = g_log_file ? g_log_file : stderr;
@@ -114,6 +127,9 @@ inline void log(LogLevel level, const char* category, const char* format, ...) {
114127

115128
fprintf(out, "\n");
116129
fflush(out);
130+
#ifdef _WIN32
131+
ReleaseSRWLockShared(&g_log_lock);
132+
#endif
117133
}
118134

119135
// Convenience macros - these compile to nothing when ULTRA_LOG_DISABLE is defined

src/gui/app.cpp

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,53 @@ static void initLog() {
3636
if (g_log_initialized) return;
3737
g_log_initialized = true;
3838

39+
#ifdef _WIN32
40+
auto tryOpenLog = [](const char* path) -> FILE* {
41+
if (!path || path[0] == '\0') {
42+
return nullptr;
43+
}
44+
45+
const char* slash_back = std::strrchr(path, '\\');
46+
const char* slash_fwd = std::strrchr(path, '/');
47+
const char* sep = slash_back;
48+
if (!sep || (slash_fwd && slash_fwd > sep)) {
49+
sep = slash_fwd;
50+
}
51+
if (sep) {
52+
std::string dir(path, static_cast<size_t>(sep - path));
53+
if (!dir.empty()) {
54+
MKDIR(dir.c_str());
55+
}
56+
}
57+
58+
return std::fopen(path, "w");
59+
};
60+
61+
if (!g_gui_log_file) {
62+
g_gui_log_file = tryOpenLog("logs\\gui.log");
63+
if (g_gui_log_file) {
64+
g_gui_log_path = "logs\\gui.log";
65+
}
66+
}
67+
68+
if (!g_gui_log_file) {
69+
g_gui_log_file = tryOpenLog("gui.log");
70+
if (g_gui_log_file) {
71+
g_gui_log_path = "gui.log";
72+
}
73+
}
74+
75+
if (!g_gui_log_file) {
76+
const char* temp = std::getenv("TEMP");
77+
if (temp && temp[0] != '\0') {
78+
std::string temp_path = std::string(temp) + "\\ProjectUltra\\gui.log";
79+
g_gui_log_file = tryOpenLog(temp_path.c_str());
80+
if (g_gui_log_file) {
81+
g_gui_log_path = temp_path;
82+
}
83+
}
84+
}
85+
#else
3986
auto tryOpenLog = [](const std::filesystem::path& path) -> FILE* {
4087
std::error_code ec;
4188
if (!path.parent_path().empty()) {
@@ -47,16 +94,10 @@ static void initLog() {
4794
std::vector<std::filesystem::path> candidates;
4895
candidates.emplace_back(std::filesystem::path("logs") / "gui.log");
4996
candidates.emplace_back("gui.log");
50-
#ifdef _WIN32
51-
if (const char* temp = std::getenv("TEMP")) {
52-
candidates.emplace_back(std::filesystem::path(temp) / "ProjectUltra" / "gui.log");
53-
}
54-
#else
5597
if (const char* temp = std::getenv("TMPDIR")) {
5698
candidates.emplace_back(std::filesystem::path(temp) / "projectultra_gui.log");
5799
}
58100
candidates.emplace_back("/tmp/projectultra_gui.log");
59-
#endif
60101

61102
for (const auto& path : candidates) {
62103
g_gui_log_file = tryOpenLog(path);
@@ -65,6 +106,7 @@ static void initLog() {
65106
break;
66107
}
67108
}
109+
#endif
68110

69111
if (g_gui_log_file) {
70112
// Redirect ALL logging (modem, protocol, etc.) to this file
@@ -186,11 +228,18 @@ static const char* adaptationDirection(Modulation from_mod, CodeRate from_rate,
186228
App::App() : App(Options{}) {}
187229

188230
App::App(const Options& opts) : options_(opts), sim_ui_visible_(opts.enable_sim) {
231+
ultra::gui::startupTrace("App", "ctor-body-enter");
232+
ultra::gui::startupTrace("App", "gui-log-enter");
189233
guiLog("=== GUI Started ===");
234+
ultra::gui::startupTrace("App", "gui-log-exit");
190235
// Load persistent settings
236+
ultra::gui::startupTrace("App", "settings-load-enter");
191237
settings_.load();
238+
ultra::gui::startupTrace("App", "settings-load-exit");
192239

240+
ultra::gui::startupTrace("App", "presets-balanced-enter");
193241
config_ = presets::balanced();
242+
ultra::gui::startupTrace("App", "presets-balanced-exit");
194243

195244
if (!options_.disable_waterfall) {
196245
ultra::gui::startupTrace("App", "waterfall-create-begin");

0 commit comments

Comments
 (0)