Skip to content

Commit b663053

Browse files
committed
Allow parsing very long lines in commit messages
It's technically possible for commit messages to contain arbitrary non-NUL bytes. Our commit message parser uses a 64 KiB buffer to read lines, and if lines are too long, it will fail. We've seen some cases where commit message lines are much longer due to historical accidents. Let's raise the maximum buffer size to 1 MiB to accommodate these situations. Let's also make it easier to track problems by returning a more helpful error message if the buffer size is exceeded.
1 parent c6c142b commit b663053

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

commit.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ func (c *Commit) Decode(from io.Reader, size int64) (n int, err error) {
9696
var messageParts []string
9797

9898
s := bufio.NewScanner(from)
99+
s.Buffer(nil, 1024 * 1024)
99100
for s.Scan() {
100101
text := s.Text()
101102
n = n + len(text+"\n")
@@ -169,7 +170,7 @@ func (c *Commit) Decode(from io.Reader, size int64) (n int, err error) {
169170
c.Message = strings.Join(messageParts, "\n")
170171

171172
if err = s.Err(); err != nil {
172-
return n, err
173+
return n, fmt.Errorf("failed to parse commit buffer: %s", err)
173174
}
174175
return n, err
175176
}

commit_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,37 @@ func TestCommitDecodingWithEmptyName(t *testing.T) {
117117
assert.Equal(t, "initial commit", commit.Message)
118118
}
119119

120+
func TestCommitDecodingWithLargeCommitMessage(t *testing.T) {
121+
message := "This message text is, with newline, exactly 64 characters long. ";
122+
// This message will be exactly 1 MiB in size when part of the commit.
123+
longMessage := strings.Repeat(message, (1024 * 1024 / 64) - 1)
124+
longMessage += strings.TrimSpace(message);
125+
126+
author := &Signature{Name: "", Email: "john@example.com", When: time.Now()}
127+
committer := &Signature{Name: "", Email: "jane@example.com", When: time.Now()}
128+
129+
treeId := []byte("cccccccccccccccccccc")
130+
131+
from := new(bytes.Buffer)
132+
133+
fmt.Fprintf(from, "author %s\n", author)
134+
fmt.Fprintf(from, "committer %s\n", committer)
135+
fmt.Fprintf(from, "tree %s\n", hex.EncodeToString(treeId))
136+
fmt.Fprintf(from, "\n%s\n", longMessage)
137+
138+
flen := from.Len()
139+
140+
commit := new(Commit)
141+
n, err := commit.Decode(from, int64(flen))
142+
143+
assert.Nil(t, err)
144+
assert.Equal(t, flen, n)
145+
146+
assert.Equal(t, author.String(), commit.Author)
147+
assert.Equal(t, committer.String(), commit.Committer)
148+
assert.Equal(t, longMessage, commit.Message)
149+
}
150+
120151
func TestCommitDecodingWithMessageKeywordPrefix(t *testing.T) {
121152
author := &Signature{Name: "John Doe", Email: "john@example.com", When: time.Now()}
122153
committer := &Signature{Name: "Jane Doe", Email: "jane@example.com", When: time.Now()}

0 commit comments

Comments
 (0)