diff --git a/CHANGELOG.md b/CHANGELOG.md index cfdc166..094831b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to `bgit` are documented in this file. This project follows semantic versioning. +## 1.3.1 + +Fixed + +- Guarded oversized local and web diff/index allocation paths to avoid integer + overflow in pathological repositories. + ## 1.3.0 Added diff --git a/local_extra.go b/local_extra.go index 54d7927..b0a77b1 100644 --- a/local_extra.go +++ b/local_extra.go @@ -1216,7 +1216,7 @@ func simpleLineDiff(left, right string) []string { if left == right { return nil } - if len(a) != 0 && len(b) > 900000/len(a) { + if simpleLineDiffShouldFallback(len(a), len(b)) { return simpleWholeFileDiff(a, b) } ops := simpleLineDiffOps(a, b) @@ -1245,9 +1245,14 @@ type simpleDiffHunk struct { } func simpleLineDiffOps(a, b []string) []simpleDiffOp { - rows := make([][]int, len(a)+1) + if simpleLineDiffShouldFallback(len(a), len(b)) { + return simpleWholeFileDiffOps(a, b) + } + rowCount := len(a) + 1 + colCount := len(b) + 1 + rows := make([][]int, rowCount) for i := range rows { - rows[i] = make([]int, len(b)+1) + rows[i] = make([]int, colCount) } for i := len(a) - 1; i >= 0; i-- { for j := len(b) - 1; j >= 0; j-- { @@ -1279,6 +1284,29 @@ func simpleLineDiffOps(a, b []string) []simpleDiffOp { return ops } +func simpleLineDiffShouldFallback(leftLines, rightLines int) bool { + const maxSimpleDiffCells = 900000 + maxInt := int(^uint(0) >> 1) + if leftLines >= maxInt || rightLines >= maxInt { + return true + } + if leftLines != 0 && rightLines > maxSimpleDiffCells/leftLines { + return true + } + return false +} + +func simpleWholeFileDiffOps(a, b []string) []simpleDiffOp { + var ops []simpleDiffOp + for i, line := range a { + ops = append(ops, simpleDiffOp{kind: '-', text: line, oldLine: i + 1}) + } + for i, line := range b { + ops = append(ops, simpleDiffOp{kind: '+', text: line, newLine: i + 1}) + } + return ops +} + func simpleLineDiffHunks(ops []simpleDiffOp, context int) []simpleDiffHunk { var hunks []simpleDiffHunk for i, op := range ops { diff --git a/web.go b/web.go index a917be7..17a1b6e 100644 --- a/web.go +++ b/web.go @@ -3875,7 +3875,8 @@ func (s *webServer) fileIndexHTML(ctx context.Context, treeHash, ref string) str if len(paths) > maxInt-len(dirPaths) { return "" } - index := make([]webFileIndexEntry, 0, len(paths)+len(dirPaths)) + indexLen := len(paths) + len(dirPaths) + index := make([]webFileIndexEntry, 0, indexLen) for _, dir := range dirPaths { index = append(index, webFileIndexEntry{Path: dir, URL: webURL("tree", dir, ref), Kind: "dir"}) }