Journal insert_row as one record; keep the cursor in the buffer; fix ENABLE_ASAN

- Buffer::insert_row recorded its text and newline as two swap records
  after inserting both. A checkpoint triggered by the first (1 MiB of
  edits, or the checkpoint timer) snapshotted the newline already, and
  the second added it again on replay: recovery after undoing C-k C-k
  silently gained a blank line. It is now one record.
- Visual-line yank placed the cursor relative to its row assuming that
  row was inside the selection; after C-k a or Enter it was not, and the
  cursor ended past the end of a line or the buffer, where typed text was
  recorded for undo at a position it was not inserted at and could not
  be undone. The formula uses the nearest selected row, and run_handler
  now clamps the cursor to the buffer before and after every command.
- ENABLE_ASAN added -fsanitize=address to CMAKE_C_FLAGS only; the
  project is C++, so nothing was instrumented. Add it to
  CMAKE_CXX_FLAGS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015rcVQiiWyTzoNrsvLSaAfB
This commit is contained in:
Claude
2026-09-24 09:16:04 -07:00
committed by Kyle Isom
parent 1e312fcd0b
commit 853416f65a
5 changed files with 102 additions and 6 deletions
+13
View File
@@ -430,6 +430,19 @@ before the fix (unless noted).
indefinitely. The editor loop now retries it each second while idle
(this was also why SwapReplay_LostRecord_ResyncsWithCheckpoint was
flaky under load).
- Undoing C-k C-k (and redoing an inserted row) journaled the row and
its newline as two records; a checkpoint triggered by the first
already contained the newline, so recovery silently produced an
extra blank line.
- Visual-line yank with the cursor moved out of the selection (C-k a,
Enter) left it past the end of a line or the buffer, and text typed
there could not be undone. Every command now leaves the cursor
inside the buffer (checked in the command dispatcher).
- ENABLE_ASAN instrumented only C sources, i.e. none of the project;
it now applies to C++ as well. (Earlier "ASan clean" results in this
audit came from that uninstrumented build; the full suite has since
passed under a correctly instrumented ASan build with leak checks,
and the stress fuzzers ran with ASan and UBSan.)
**Known limitations (not fixed)**
- Catastrophic regex backtracking (e.g. `(a*)*b`) can still take very