Skip to content

Commit 77b01ca

Browse files
committed
Fix index out of bounds panic when repository has massive tag lists
1 parent 143d476 commit 77b01ca

File tree

2 files changed

+80
-4
lines changed

2 files changed

+80
-4
lines changed

pkg/commands/git_commands/commit_loader.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ func (self *CommitLoader) GetCommits(opts GetCommitsOptions) ([]*models.Commit,
9191

9292
logErr = self.getLogCmd(opts).RunAndProcessLines(func(line string) (bool, error) {
9393
commit := self.extractCommitFromLine(opts.HashPool, line, opts.RefToShowDivergenceFrom != "")
94-
commits = append(commits, commit)
94+
if commit != nil {
95+
commits = append(commits, commit)
96+
}
9597
return false, nil
9698
})
9799
})
@@ -200,17 +202,33 @@ func (self *CommitLoader) MergeRebasingCommits(hashPool *utils.StringPool, commi
200202
func (self *CommitLoader) extractCommitFromLine(hashPool *utils.StringPool, line string, showDivergence bool) *models.Commit {
201203
split := strings.SplitN(line, "\x00", 8)
202204

205+
// Ensure we have the minimum required fields (at least 5 for basic functionality)
206+
if len(split) < 5 {
207+
self.Log.Warnf("Malformed git log line: expected at least 5 fields, got %d. Line: %s", len(split), line)
208+
return nil
209+
}
210+
203211
hash := split[0]
204212
unixTimestamp := split[1]
205213
authorName := split[2]
206214
authorEmail := split[3]
207215
extraInfo := strings.TrimSpace(split[4])
208-
parentHashes := split[5]
216+
217+
// Safe access to optional fields with defaults
218+
parentHashes := ""
219+
if len(split) > 5 {
220+
parentHashes = split[5]
221+
}
222+
209223
divergence := models.DivergenceNone
210-
if showDivergence {
224+
if showDivergence && len(split) > 6 {
211225
divergence = lo.Ternary(split[6] == "<", models.DivergenceLeft, models.DivergenceRight)
212226
}
213-
message := split[7]
227+
228+
message := ""
229+
if len(split) > 7 {
230+
message = split[7]
231+
}
214232

215233
tags := []string{}
216234

pkg/commands/git_commands/commit_loader_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,3 +588,61 @@ func TestCommitLoader_setCommitMergedStatuses(t *testing.T) {
588588
})
589589
}
590590
}
591+
592+
func TestCommitLoader_extractCommitFromLine(t *testing.T) {
593+
common := common.NewDummyCommon()
594+
hashPool := &utils.StringPool{}
595+
596+
loader := &CommitLoader{
597+
Common: common,
598+
}
599+
600+
scenarios := []struct {
601+
testName string
602+
line string
603+
showDivergence bool
604+
expectedNil bool
605+
}{
606+
{
607+
testName: "normal commit line",
608+
line: "0eea75e8c631fba6b58135697835d58ba4c18dbc\x001640826609\x00Jesse Duffield\x00jessedduffield@gmail.com\x00HEAD -> better-tests\x00b21997d6b4cbdf84b149\x00>\x00better typing for rebase mode",
609+
showDivergence: true,
610+
expectedNil: false,
611+
},
612+
{
613+
testName: "malformed line with only 3 fields",
614+
line: "hash\x00timestamp\x00author",
615+
showDivergence: false,
616+
expectedNil: true,
617+
},
618+
{
619+
testName: "malformed line with only 4 fields",
620+
line: "hash\x00timestamp\x00author\x00email",
621+
showDivergence: false,
622+
expectedNil: true,
623+
},
624+
{
625+
testName: "minimal valid line with 5 fields",
626+
line: "hash\x00timestamp\x00author\x00email\x00extraInfo",
627+
showDivergence: false,
628+
expectedNil: false,
629+
},
630+
{
631+
testName: "line missing divergence field when expected",
632+
line: "hash\x00timestamp\x00author\x00email\x00extraInfo\x00parents",
633+
showDivergence: true,
634+
expectedNil: false,
635+
},
636+
}
637+
638+
for _, scenario := range scenarios {
639+
t.Run(scenario.testName, func(t *testing.T) {
640+
result := loader.extractCommitFromLine(hashPool, scenario.line, scenario.showDivergence)
641+
if scenario.expectedNil {
642+
assert.Nil(t, result)
643+
} else {
644+
assert.NotNil(t, result)
645+
}
646+
})
647+
}
648+
}

0 commit comments

Comments
 (0)