Fix plain mbox reader buffer aliasing

This commit is contained in:
DonVoo 2026-07-15 00:57:16 +02:00
parent e63a513cff
commit 6c4073a01c
3 changed files with 134 additions and 2 deletions

View file

@ -439,7 +439,7 @@ func readMboxMessagesBytes(b []byte) [][]byte {
for _, line := range lines {
if bytes.HasPrefix(line, []byte("From ")) {
if inMsg && cur.Len() > 0 {
msgs = append(msgs, bytes.TrimRight(cur.Bytes(), "\n"))
msgs = append(msgs, cloneTrimmedMessage(cur.Bytes()))
cur.Reset()
}
inMsg = true
@ -455,11 +455,16 @@ func readMboxMessagesBytes(b []byte) [][]byte {
_ = cur.WriteByte('\n')
}
if inMsg && cur.Len() > 0 {
msgs = append(msgs, bytes.TrimRight(cur.Bytes(), "\n"))
msgs = append(msgs, cloneTrimmedMessage(cur.Bytes()))
}
return msgs
}
func cloneTrimmedMessage(b []byte) []byte {
trimmed := bytes.TrimRight(b, "\n")
return append([]byte(nil), trimmed...)
}
func readMboxListFromIndex(path string) ([]MboxEntry, bool) {
accountID, folder, ok := mboxIndexContext(path)
if !ok {

View file

@ -4,6 +4,7 @@ import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
"time"
@ -203,6 +204,42 @@ func TestPlainMboxPartialIndexIsRebuiltBeforeList(t *testing.T) {
}
}
func TestReadMboxMessagesBytesClonesBufferRecords(t *testing.T) {
mbox := []byte(strings.Join([]string{
"From one@example.com Tue Jul 14 10:00:00 2026",
"Message-ID: <one@example.com>",
"Subject: One",
"",
"short",
"From two@example.com Tue Jul 14 10:01:00 2026",
"Message-ID: <two@example.com>",
"Subject: Two",
"",
"this message is deliberately much longer than the first one",
"and has another line",
"From three@example.com Tue Jul 14 10:02:00 2026",
"Message-ID: <three@example.com>",
"Subject: Three",
"",
"tiny",
"",
}, "\n"))
msgs := readMboxMessagesBytes(mbox)
if len(msgs) != 3 {
t.Fatalf("expected 3 messages, got %d", len(msgs))
}
wants := []string{"Subject: One", "Subject: Two", "Subject: Three"}
for i, want := range wants {
if !bytes.Contains(msgs[i], []byte(want)) {
t.Fatalf("message %d does not contain %q: %q", i, want, msgs[i])
}
}
if bytes.Contains(msgs[0], []byte("Subject: Two")) || bytes.Contains(msgs[1], []byte("Subject: Three")) {
t.Fatalf("messages share buffer contents: %#q", msgs)
}
}
func testRawMessage(id, subject string) RawMessage {
return RawMessage{
MessageID: id,