From e3b63c085621405ab211d95df7a80ce9637b5098 Mon Sep 17 00:00:00 2001 From: Mollusk Date: Mon, 1 Jun 2026 15:43:08 -0400 Subject: [PATCH] fix: make log_msg writes atomic Each log_msg opened the file in O_APPEND mode then used writeln!, which issues a separate write() syscall per formatting fragment. O_APPEND only guarantees atomicity per write() call, so concurrent log_msg calls from the app's many threads/tasks could interleave their fragments mid-line. Format the full line (timestamp + msg + newline) into one String, then emit it with a single write_all so each log line lands as one atomic append. No behavior change beyond non-interleaved output. Co-Authored-By: Claude Opus 4.8 --- src/lib.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 11671f2..a8f7210 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,17 +32,21 @@ pub fn log_file_path() -> PathBuf { } pub fn log_msg(msg: &str) { + // Format the whole line into one buffer first, then emit it with a single + // `write_all`. The file is opened with `O_APPEND`, so a lone `write()` is + // atomic w.r.t. concurrent writers; building the line up front avoids the + // multi-syscall `writeln!` path that would let threads interleave fragments. + let line = match std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) { + Ok(time) => format!("[{}.{:03}] {}\n", time.as_secs(), time.subsec_millis(), msg), + Err(_) => format!("{}\n", msg), + }; if let Ok(mut file) = std::fs::OpenOptions::new() .create(true) .append(true) .open(log_path()) { use std::io::Write; - if let Ok(time) = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) { - let _ = writeln!(file, "[{}.{:03}] {}", time.as_secs(), time.subsec_millis(), msg); - } else { - let _ = writeln!(file, "{}", msg); - } + let _ = file.write_all(line.as_bytes()); } }