From faf77de9ce9dfc72f748d4963d591be0322bd3e3 Mon Sep 17 00:00:00 2001 From: DanS Date: Wed, 15 Jul 2026 23:09:04 -0500 Subject: [PATCH] fix(console): stop the Clear button crashing the tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit render() computes visible_indices_ (indices into model_) once per frame at the top, before the toolbar. The toolbar's Clear button called clear() → model_.clear(), emptying model_ mid-frame (the "cleared" marker is only queued, drained next frame). renderOutput() then indexed model_[visible_indices_[vi]] with the stale indices → out-of-bounds → crash. clear() now also drops visible_indices_ and the selection (both hold line indices into model_), so this frame's renderOutput iterates zero lines and computeVisibleLines rebuilds them next frame. The right-click "Clear console" menu item now routes through clear() instead of a bare model_.clear() so it's covered too. Adversarially verified: no other same-frame path indexes the emptied model (fold-toggle, ingest, and selectAll are bounds-guarded). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/ui/windows/console_tab.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ui/windows/console_tab.cpp b/src/ui/windows/console_tab.cpp index 66bd58f..575512f 100644 --- a/src/ui/windows/console_tab.cpp +++ b/src/ui/windows/console_tab.cpp @@ -511,8 +511,7 @@ void ConsoleTab::renderToolbar(ConsoleCommandExecutor& exec) // Clear button if (TactileButton(TR("console_clear"), ImVec2(0, 0), schema::UI().resolveFont("button"))) { - clear(); - selection_.clear(); + clear(); // also drops the stale visible_indices_ + selection (see ConsoleTab::clear) } ImGui::SameLine(); @@ -1183,9 +1182,9 @@ void ConsoleTab::drawOutputContextMenu() } ImGui::Separator(); if (ImGui::MenuItem(TR("console_clear_console"))) { - // View-only clear (main thread) — drop the visible lines and the selection. - model_.clear(); - selection_.clear(); + // View-only clear — route through clear() so the stale visible_indices_/selection are dropped too + // (a bare model_.clear() mid-frame would leave renderOutput() indexing the emptied model_ → crash). + clear(); } ImGui::EndPopup(); } @@ -2004,6 +2003,12 @@ void ConsoleTab::clear() // View-only clear (main thread). The executor keeps its own log cursors, so new output // still appends. The "cleared" line is ingested and appears on the next frame's drain. model_.clear(); + // visible_indices_ was computed at the top of render() (line 311), BEFORE the toolbar's Clear button + // ran; those indices now point past the emptied model_. renderOutput() (this same frame, after the + // toolbar) indexes model_[visible_indices_[vi]] — so drop them (and the selection, which also holds + // line indices) here to avoid an out-of-bounds crash. computeVisibleLines() rebuilds them next frame. + visible_indices_.clear(); + selection_.clear(); stop_confirm_pending_ = false; // a pending 'stop' confirmation is cancelled by clearing addLine(TR("console_cleared"), ConsoleChannel::Info); }