Prevent panic on git blame by limiting lines to 4096 bytes at most (#13492)

Fix #12440
Closes #13192

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
6543 2020-11-10 08:59:38 +01:00 committed by GitHub
parent 0f2ee77968
commit 4a71d4de68
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -27,7 +27,7 @@ type BlameReader struct {
cmd *exec.Cmd cmd *exec.Cmd
pid int64 pid int64
output io.ReadCloser output io.ReadCloser
scanner *bufio.Scanner reader *bufio.Reader
lastSha *string lastSha *string
cancel context.CancelFunc cancel context.CancelFunc
} }
@ -38,23 +38,30 @@ var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
func (r *BlameReader) NextPart() (*BlamePart, error) { func (r *BlameReader) NextPart() (*BlamePart, error) {
var blamePart *BlamePart var blamePart *BlamePart
scanner := r.scanner reader := r.reader
if r.lastSha != nil { if r.lastSha != nil {
blamePart = &BlamePart{*r.lastSha, make([]string, 0)} blamePart = &BlamePart{*r.lastSha, make([]string, 0)}
} }
for scanner.Scan() { var line []byte
line := scanner.Text() var isPrefix bool
var err error
for err != io.EOF {
line, isPrefix, err = reader.ReadLine()
if err != nil && err != io.EOF {
return blamePart, err
}
// Skip empty lines
if len(line) == 0 { if len(line) == 0 {
// isPrefix will be false
continue continue
} }
lines := shaLineRegex.FindStringSubmatch(line) lines := shaLineRegex.FindSubmatch(line)
if lines != nil { if lines != nil {
sha1 := lines[1] sha1 := string(lines[1])
if blamePart == nil { if blamePart == nil {
blamePart = &BlamePart{sha1, make([]string, 0)} blamePart = &BlamePart{sha1, make([]string, 0)}
@ -62,12 +69,27 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
if blamePart.Sha != sha1 { if blamePart.Sha != sha1 {
r.lastSha = &sha1 r.lastSha = &sha1
// need to munch to end of line...
for isPrefix {
_, isPrefix, err = reader.ReadLine()
if err != nil && err != io.EOF {
return blamePart, err
}
}
return blamePart, nil return blamePart, nil
} }
} else if line[0] == '\t' { } else if line[0] == '\t' {
code := line[1:] code := line[1:]
blamePart.Lines = append(blamePart.Lines, code) blamePart.Lines = append(blamePart.Lines, string(code))
}
// need to munch to end of line...
for isPrefix {
_, isPrefix, err = reader.ReadLine()
if err != nil && err != io.EOF {
return blamePart, err
}
} }
} }
@ -121,13 +143,13 @@ func createBlameReader(ctx context.Context, dir string, command ...string) (*Bla
pid := process.GetManager().Add(fmt.Sprintf("GetBlame [repo_path: %s]", dir), cancel) pid := process.GetManager().Add(fmt.Sprintf("GetBlame [repo_path: %s]", dir), cancel)
scanner := bufio.NewScanner(stdout) reader := bufio.NewReader(stdout)
return &BlameReader{ return &BlameReader{
cmd, cmd,
pid, pid,
stdout, stdout,
scanner, reader,
nil, nil,
cancel, cancel,
}, nil }, nil