Skip to content

Commit d39e28e

Browse files
rscharfegitster
authored andcommitted
xdiff: avoid arithmetic overflow in xdl_get_hunk()
xdl_get_hunk() calculates the maximum number of common lines between two changes that would fit into the same hunk for the given context options. It involves doubling and addition and thus can overflow if the terms are huge. The type of ctxlen and interhunkctxlen in xdemitconf_t is long, while the type of the corresponding context and interhunkcontext in struct diff_options is int. On many platforms longs are bigger that ints, which prevents the overflow. On Windows they have the same range and the overflow manifests as hunks that are split erroneously and lines being repeated between them. Fix the overflow by checking and not going beyond LONG_MAX. This allows specifying a huge context line count and getting all lines of a changed files in a single hunk, as expected. Reported-by: Jason Cho <[email protected]> Signed-off-by: René Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5c21db3 commit d39e28e

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

t/t4055-diff-context.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,14 @@ test_expect_success '-U0 is valid, so is diff.context=0' '
9090
grep "^+MODIFIED" output
9191
'
9292

93+
test_expect_success '-U2147483647 works' '
94+
echo APPENDED >>x &&
95+
test_line_count = 16 x &&
96+
git diff -U2147483647 >output &&
97+
test_line_count = 22 output &&
98+
grep "^-ADDED" output &&
99+
grep "^+MODIFIED" output &&
100+
grep "^+APPENDED" output
101+
'
102+
93103
test_done

xdiff/xemit.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *
4343
return 0;
4444
}
4545

46+
static long saturating_add(long a, long b)
47+
{
48+
return signed_add_overflows(a, b) ? LONG_MAX : a + b;
49+
}
4650

4751
/*
4852
* Starting at the passed change atom, find the latest change atom to be included
@@ -52,7 +56,9 @@ static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *
5256
xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
5357
{
5458
xdchange_t *xch, *xchp, *lxch;
55-
long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen;
59+
long max_common = saturating_add(saturating_add(xecfg->ctxlen,
60+
xecfg->ctxlen),
61+
xecfg->interhunkctxlen);
5662
long max_ignorable = xecfg->ctxlen;
5763
unsigned long ignored = 0; /* number of ignored blank lines */
5864

0 commit comments

Comments
 (0)