]> source.dussan.org Git - gitea.git/commitdiff
Limit the max line length when parsing git grep output (#30418)
authorwxiaoguang <wxiaoguang@gmail.com>
Fri, 12 Apr 2024 03:36:34 +0000 (11:36 +0800)
committerGitHub <noreply@github.com>
Fri, 12 Apr 2024 03:36:34 +0000 (03:36 +0000)
modules/git/grep.go
modules/git/grep_test.go

index a6c486112a5f64b83bffafd474285af4014bf072..e7d238e586aa44185093b2fff8fb51c5499af047 100644 (file)
@@ -10,6 +10,7 @@ import (
        "errors"
        "fmt"
        "os"
+       "slices"
        "strconv"
        "strings"
 
@@ -27,6 +28,7 @@ type GrepOptions struct {
        MaxResultLimit    int
        ContextLineNumber int
        IsFuzzy           bool
+       MaxLineLength     int // the maximum length of a line to parse, exceeding chars will be truncated
 }
 
 func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepOptions) ([]*GrepResult, error) {
@@ -71,10 +73,20 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
                        defer stdoutReader.Close()
 
                        isInBlock := false
-                       scanner := bufio.NewScanner(stdoutReader)
+                       rd := bufio.NewReaderSize(stdoutReader, util.IfZero(opts.MaxLineLength, 16*1024))
                        var res *GrepResult
-                       for scanner.Scan() {
-                               line := scanner.Text()
+                       for {
+                               lineBytes, isPrefix, err := rd.ReadLine()
+                               if isPrefix {
+                                       lineBytes = slices.Clone(lineBytes)
+                                       for isPrefix && err == nil {
+                                               _, isPrefix, err = rd.ReadLine()
+                                       }
+                               }
+                               if len(lineBytes) == 0 && err != nil {
+                                       break
+                               }
+                               line := string(lineBytes) // the memory of lineBytes is mutable
                                if !isInBlock {
                                        if _ /* ref */, filename, ok := strings.Cut(line, ":"); ok {
                                                isInBlock = true
@@ -100,7 +112,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
                                        res.LineCodes = append(res.LineCodes, lineCode)
                                }
                        }
-                       return scanner.Err()
+                       return nil
                },
        })
        // git grep exits by cancel (killed), usually it is caused by the limit of results
index b5fa437c53f8c9df8096baaffaf48f89da67ff39..7f4ded478f57188d1fb9e29e071efde248183048 100644 (file)
@@ -41,6 +41,16 @@ func TestGrepSearch(t *testing.T) {
                },
        }, res)
 
+       res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{MaxResultLimit: 1, MaxLineLength: 39})
+       assert.NoError(t, err)
+       assert.Equal(t, []*GrepResult{
+               {
+                       Filename:    "java-hello/main.java",
+                       LineNumbers: []int{3},
+                       LineCodes:   []string{" public static void main(String[] arg"},
+               },
+       }, res)
+
        res, err = GrepSearch(context.Background(), repo, "no-such-content", GrepOptions{})
        assert.NoError(t, err)
        assert.Len(t, res, 0)