fix(console): stop the Clear button crashing the tab
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) <noreply@anthropic.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user