Skip to content

Commit 6f04ee2

Browse files
chojs23stefanhaller
andcommitted
Fix index out of bounds panic when repository has massive tag lists
Co-authored-by: Stefan Haller <stefan@haller-berlin.de>
1 parent c54232e commit 6f04ee2

File tree

2 files changed

+124
-1
lines changed

2 files changed

+124
-1
lines changed

pkg/commands/git_commands/commit_loader.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,12 @@ func (self *CommitLoader) MergeRebasingCommits(hashPool *utils.StringPool, commi
202202
func (self *CommitLoader) extractCommitFromLine(hashPool *utils.StringPool, line string, showDivergence bool) *models.Commit {
203203
split := strings.SplitN(line, "\x00", 8)
204204

205+
// Ensure we have the minimum required fields (at least 7 for basic functionality)
206+
if len(split) < 7 {
207+
self.Log.Warnf("Malformed git log line: expected at least 7 fields, got %d. Line: %s", len(split), line)
208+
return nil
209+
}
210+
205211
hash := split[0]
206212
unixTimestamp := split[1]
207213
authorName := split[2]
@@ -212,7 +218,12 @@ func (self *CommitLoader) extractCommitFromLine(hashPool *utils.StringPool, line
212218
divergence = lo.Ternary(split[5] == "<", models.DivergenceLeft, models.DivergenceRight)
213219
}
214220
extraInfo := strings.TrimSpace(split[6])
215-
message := split[7]
221+
222+
// message (and the \x00 before it) might not be present if extraInfo is extremely long
223+
message := ""
224+
if len(split) > 7 {
225+
message = split[7]
226+
}
216227

217228
var tags []string
218229

pkg/commands/git_commands/commit_loader_test.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,3 +588,115 @@ 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 with all fields",
608+
line: "0eea75e8c631fba6b58135697835d58ba4c18dbc\x001640826609\x00Jesse Duffield\x00jessedduffield@gmail.com\x00b21997d6b4cbdf84b149\x00>\x00HEAD -> better-tests\x00better typing for rebase mode",
609+
showDivergence: true,
610+
expectedNil: false,
611+
},
612+
{
613+
testName: "normal commit line with left divergence",
614+
line: "hash123\x001234567890\x00John Doe\x00john@example.com\x00parent1 parent2\x00<\x00origin/main\x00commit message",
615+
showDivergence: true,
616+
expectedNil: false,
617+
},
618+
{
619+
testName: "commit line with tags in extraInfo",
620+
line: "abc123\x001640000000\x00Jane Smith\x00jane@example.com\x00parenthash\x00>\x00tag: v1.0, tag: release\x00tagged release",
621+
showDivergence: true,
622+
expectedNil: false,
623+
},
624+
{
625+
testName: "commit line with empty extraInfo",
626+
line: "def456\x001640000000\x00Bob Wilson\x00bob@example.com\x00parenthash\x00>\x00\x00simple commit",
627+
showDivergence: true,
628+
expectedNil: false,
629+
},
630+
{
631+
testName: "commit line with no parents (root commit)",
632+
line: "root123\x001640000000\x00Alice Cooper\x00alice@example.com\x00\x00>\x00\x00initial commit",
633+
showDivergence: true,
634+
expectedNil: false,
635+
},
636+
{
637+
testName: "malformed line with only 3 fields",
638+
line: "hash\x00timestamp\x00author",
639+
showDivergence: false,
640+
expectedNil: true,
641+
},
642+
{
643+
testName: "malformed line with only 4 fields",
644+
line: "hash\x00timestamp\x00author\x00email",
645+
showDivergence: false,
646+
expectedNil: true,
647+
},
648+
{
649+
testName: "malformed line with only 5 fields",
650+
line: "hash\x00timestamp\x00author\x00email\x00parents",
651+
showDivergence: false,
652+
expectedNil: true,
653+
},
654+
{
655+
testName: "malformed line with only 6 fields",
656+
line: "hash\x00timestamp\x00author\x00email\x00parents\x00<",
657+
showDivergence: true,
658+
expectedNil: true,
659+
},
660+
{
661+
testName: "minimal valid line with 7 fields (no message)",
662+
line: "hash\x00timestamp\x00author\x00email\x00parents\x00>\x00extraInfo",
663+
showDivergence: true,
664+
expectedNil: false,
665+
},
666+
{
667+
testName: "minimal valid line with 7 fields (empty extraInfo)",
668+
line: "hash\x00timestamp\x00author\x00email\x00parents\x00>\x00",
669+
showDivergence: true,
670+
expectedNil: false,
671+
},
672+
{
673+
testName: "valid line with 8 fields (complete)",
674+
line: "hash\x00timestamp\x00author\x00email\x00parents\x00<\x00extraInfo\x00message",
675+
showDivergence: true,
676+
expectedNil: false,
677+
},
678+
{
679+
testName: "empty line",
680+
line: "",
681+
showDivergence: false,
682+
expectedNil: true,
683+
},
684+
{
685+
testName: "line with special characters in commit message",
686+
line: "special123\x001640000000\x00Dev User\x00dev@example.com\x00parenthash\x00>\x00\x00fix: handle \x00 null bytes and 'quotes'",
687+
showDivergence: true,
688+
expectedNil: false,
689+
},
690+
}
691+
692+
for _, scenario := range scenarios {
693+
t.Run(scenario.testName, func(t *testing.T) {
694+
result := loader.extractCommitFromLine(hashPool, scenario.line, scenario.showDivergence)
695+
if scenario.expectedNil {
696+
assert.Nil(t, result)
697+
} else {
698+
assert.NotNil(t, result)
699+
}
700+
})
701+
}
702+
}

0 commit comments

Comments
 (0)