Skip to content

Commit b272a60

Browse files
committed
clamp history cursor in SetCurrent to avoid out-of-bounds panics
1 parent 9001993 commit b272a60

2 files changed

Lines changed: 35 additions & 3 deletions

File tree

pkg/history/history.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,11 @@ func (h *History) Next() string {
7171
return h.Messages[h.current]
7272
}
7373

74-
// SetCurrent positions the cursor at index i.
74+
// SetCurrent positions the cursor at index i, clamped to [0, len(Messages)].
75+
// Keeping the cursor in this range guarantees that subsequent Previous and
76+
// Next calls never index out of bounds.
7577
func (h *History) SetCurrent(i int) {
76-
h.current = i
78+
h.current = max(0, min(i, len(h.Messages)))
7779
}
7880

7981
// LatestMatch returns the most recent entry that strictly extends prefix, or
@@ -152,7 +154,7 @@ func (h *History) load() error {
152154
}
153155

154156
for line := range bytes.Lines(data) {
155-
line = bytes.TrimRight(line, "\n")
157+
line = bytes.TrimSuffix(line, []byte("\n"))
156158
if len(line) == 0 {
157159
continue
158160
}

pkg/history/history_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,36 @@ func TestHistory_SetCurrent(t *testing.T) {
418418
assert.Empty(t, h.Next())
419419
}
420420

421+
func TestHistory_SetCurrentOutOfRange(t *testing.T) {
422+
t.Parallel()
423+
tmpDir := t.TempDir()
424+
h, err := New(tmpDir)
425+
require.NoError(t, err)
426+
427+
require.NoError(t, h.Add("first"))
428+
require.NoError(t, h.Add("second"))
429+
430+
// A negative value clamps to 0; Previous returns the oldest entry.
431+
h.SetCurrent(-5)
432+
assert.Equal(t, "first", h.Previous())
433+
434+
// A value past the end clamps to len(Messages); Next returns empty.
435+
h.SetCurrent(100)
436+
assert.Empty(t, h.Next())
437+
438+
// And from the clamped position, Previous returns the latest entry.
439+
h.SetCurrent(100)
440+
assert.Equal(t, "second", h.Previous())
441+
442+
// On empty history, SetCurrent never causes a panic.
443+
empty, err := New(t.TempDir())
444+
require.NoError(t, err)
445+
empty.SetCurrent(-5)
446+
assert.Empty(t, empty.Previous())
447+
empty.SetCurrent(100)
448+
assert.Empty(t, empty.Next())
449+
}
450+
421451
func TestHistory_VeryLongMessage(t *testing.T) {
422452
tmpDir := t.TempDir()
423453

0 commit comments

Comments
 (0)