Skip to content

fix(editor): free the two undo lists readline 8.1 drops on the floor - #180

Merged
LESdylan merged 1 commit into
developfrom
fix/rl-saved-line-leak
Oct 18, 2026
Merged

LESdylan merged 1 commit into
developfrom
fix/rl-saved-line-leak

Conversation

@LESdylan

Copy link
Copy Markdown
Member

ASan reported a leak at exit after normal editing (32 bytes + typed text, from rl_add_undo). Two readline 8.1 paths lose an undo list once per line; the in-process reader made them ours. Both predate #136/#140.

  • Saved line — type, walk history with previous-history (Ctrl-P, or Up with prefix search off), end on the recalled entry: the next readline() freed the saved copy but not its undo list. hist_rl_reclaim_saved() takes it back before each read with public calls only (rl_maybe_save_line / rl_maybe_unsave_line / rl_free_undo_list).
  • Aborted search — Alt-N / Alt-P, type, abort (^G, ^C, Rubout on empty): the search string's undo list was overwritten. rl_nsearch_reclaim() frees it in the reader on the aborting byte (Caveat-marked: the abort keys mirror 8.1's search.c).

tests/rl_undo_leak_test.py: 10 leaking sequences with detect_leaks=1 + 3 "keys still work" checks. Before 11 failed, after 0. SKIP without ASan.

🤖 Generated with Claude Code

ASan reported a leak at exit after an ordinary editing session: 32 bytes
plus the typed text, allocated by readline's rl_add_undo. Two paths in
readline 8.1 (Ubuntu 22.04's, what the 42 machines link) lose an undo
list once per line, and the in-process reader made them the shell's:

- Saved line. Walking the history from a typed line with
  previous-history (Ctrl-P, or Up when prefix search is off) saves that
  line, with its undo list as data, so Down can bring it back. Ended on
  the recalled entry (Enter, ^C, ^G), the saved copy outlives the read
  and the next readline() frees it without its data.
  hist_rl_reclaim_saved() now runs before each read and takes the list
  back with public calls only: rl_maybe_save_line() so there is a saved
  line (unsave rings the bell otherwise), rl_maybe_unsave_line() to move
  its data into rl_undo_list, rl_free_undo_list() to free it, which also
  clears any history entry still pointing at it.
- Aborted search. Alt-N / Alt-P (stock non-incremental search) reads its
  string with an undo list of its own; aborting restores the saved line
  over rl_undo_list. rl_nsearch_reclaim() frees that list in the reader
  when the byte readline is about to get ends the search: ^G, ^C, Rubout
  or ^H on an empty string, a failed read. A readline that frees it
  itself finds NULL. Marked Caveat: the abort keys mirror 8.1's search.c.

Both predate #136/#140 (same report on 134ac5a); prefix search made the
first one the everyday path on a non-PIE build, where Up was plain
previous-history.

tests/rl_undo_leak_test.py runs 10 leaking key sequences, each in a fresh
shell with detect_leaks=1, plus 3 checks that the keys still work (Up
then Down restores the typed line, Alt-P finds, ^G restores). Before:
11 failed; after: 0. SKIP on a binary built without ASan.
@LESdylan
LESdylan merged commit 44ba84f into develop Oct 18, 2026
35 checks passed
@LESdylan
LESdylan deleted the fix/rl-saved-line-leak branch October 18, 2026 02:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant