From 19b71a98b7a74221a66d5dc6b84bc86b07d88284 Mon Sep 17 00:00:00 2001 From: xirvik Date: Sat, 19 Sep 2026 01:58:17 +0000 Subject: [PATCH] Fix data race reading the log buffer from the display thread Copy entries under the buffer lock before rendering; other threads mutate the deque. --- src/display/window_log.cc | 26 ++++++++++++++++++++------ src/display/window_log_complete.cc | 24 ++++++++++++++++++------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/display/window_log.cc b/src/display/window_log.cc index 9ab3016a..756bb340 100644 --- a/src/display/window_log.cc +++ b/src/display/window_log.cc @@ -1,6 +1,8 @@ #include "config.h" #include +#include +#include #include #include #include @@ -41,13 +43,20 @@ WindowLog::redraw() { int pos = m_canvas->height(); - for (iterator itr = m_log->end(), last = find_older(); itr != last && pos > 0; --pos) { - itr--; + std::vector entries; + { + std::lock_guard guard(*m_log); + + for (iterator itr = m_log->end(), last = find_older(); itr != last && entries.size() < static_cast(pos); ) + entries.push_back(*--itr); + } + + for (const auto& entry : entries) { char buffer[16]; - print_hhmmss_local(buffer, buffer + 16, static_cast(itr->timestamp)); + print_hhmmss_local(buffer, buffer + 16, static_cast(entry.timestamp)); - m_canvas->print(0, pos - 1, "(%s) %s", buffer, itr->message.c_str()); + m_canvas->print(0, --pos, "(%s) %s", buffer, entry.message.c_str()); } } @@ -60,8 +69,13 @@ WindowLog::receive_update() { if (!is_active()) return; - auto itr = find_older(); - auto height = std::min(std::distance(itr, (iterator)m_log->end()), (std::iterator_traits::difference_type)10); + std::iterator_traits::difference_type height; + + { + std::lock_guard guard(*m_log); + + height = std::min(std::distance(find_older(), (iterator)m_log->end()), (std::iterator_traits::difference_type)10); + } if (height != m_max_height) { m_min_height = height != 0 ? 1 : 0; diff --git a/src/display/window_log_complete.cc b/src/display/window_log_complete.cc index d84b3d30..de70ed1e 100644 --- a/src/display/window_log_complete.cc +++ b/src/display/window_log_complete.cc @@ -1,6 +1,8 @@ #include "config.h" #include +#include +#include #include "canvas.h" #include "utils.h" @@ -29,24 +31,34 @@ WindowLogComplete::redraw() { int pos = m_canvas->height(); - for (iterator itr = m_log->end(), last = m_log->begin(); itr != last && pos > 0; ) { - itr--; + std::vector entries; + + { + std::lock_guard guard(*m_log); + + for (iterator itr = m_log->end(), last = m_log->begin(); itr != last && entries.size() < static_cast(pos); ) + entries.push_back(*--itr); + } + + for (const auto& entry : entries) { + if (pos <= 0) + break; char buffer[16]; // Use an arbitrary min width of 60 for allowing multiple // lines. This should ensure we don't mess up the display when the // screen is shrunk too much. - unsigned int timeWidth = 3 + print_hhmmss_local(buffer, buffer + 16, static_cast(itr->timestamp)) - buffer; + unsigned int timeWidth = 3 + print_hhmmss_local(buffer, buffer + 16, static_cast(entry.timestamp)) - buffer; unsigned int logWidth = m_canvas->width() > 60 ? (m_canvas->width() - timeWidth) : (60 - timeWidth); - unsigned int logHeight = (itr->message.size() + logWidth - 1) / logWidth; + unsigned int logHeight = (entry.message.size() + logWidth - 1) / logWidth; for (unsigned int j = logHeight; j > 0 && pos > 0; --j, --pos) if (j == 1) - m_canvas->print(0, pos - 1, "(%s) %s", buffer, itr->message.substr(0, m_canvas->width() - timeWidth).c_str()); + m_canvas->print(0, pos - 1, "(%s) %s", buffer, entry.message.substr(0, m_canvas->width() - timeWidth).c_str()); else - m_canvas->print(timeWidth, pos - 1, "%s", itr->message.substr(logWidth * (j - 1), m_canvas->width() - timeWidth).c_str()); + m_canvas->print(timeWidth, pos - 1, "%s", entry.message.substr(logWidth * (j - 1), m_canvas->width() - timeWidth).c_str()); } }