xdiff: clamp function context indices in post-image

After finding a function line for --function-context in the pre-image, xdl_emit_diff() calculates the equivalent line in the post-image. It assumes that the lines between changes are the same on both sides. If the option --ignore-blank-lines was also given then this is not necessarily true. Clamp the calculation results for start and end of the function context to prevent out-of-bounds array accesses. Note that this _just_ fixes the case where our mismatch sends us off the beginning of the file. There are likely other cases where our assumption causes us to go to the wrong line within the file. Nobody has developed a test case yet, and the ultimate fix is likely more complicated than this patch. But this at least prevents a segfault in the meantime. Credit for finding the bug goes to "Liu Wei of Tencent Security Xuanwu Lab". Reported-by: 刘炜 <lw17qhdz@gmail.com> Helped-by: René Scharfe <l.s.r@web.de> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Jul 23, 2019 at 15:27 UTC b777f3fd619ac2af507ffd3e7c5fe0d6e36e81f2
2 files changed +24 -2
t/t4015-diff-whitespace.sh
+22
@@ -1897,4 +1897,26 @@ test_expect_success 'compare whitespace delta incompatible with other space opti
1897 test_i18ngrep allow-indentation-change err
1898 '
1899
1900 +# Note that the "6" in the expected hunk header below is funny, since we only
1901 +# show 5 lines (the missing one was blank and thus ignored). This is how
1902 +# --ignore-blank-lines behaves even without --function-context, and this test
1903 +# is just checking the interaction of the two features. Don't take it as an
1904 +# endorsement of that output.
1905 +test_expect_success 'combine --ignore-blank-lines with --function-context' '
1906 + test_write_lines 1 "" 2 3 4 5 >a &&
1907 + test_write_lines 1 2 3 4 >b &&
1908 + test_must_fail git diff --no-index \
1909 + --ignore-blank-lines --function-context a b >actual.raw &&
1910 + sed -n "/@@/,\$p" <actual.raw >actual &&
1911 + cat <<-\EOF >expect &&
1912 + @@ -1,6 +1,4 @@
1913 + 1
1914 + 2
1915 + 3
1916 + 4
1917 + -5
1918 + EOF
1919 + test_cmp expect actual
1920 +'
1921 +
1922 test_done
xdiff/xemit.c
+2 -2
@@ -210,7 +210,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
210 if (fs1 < 0)
211 fs1 = 0;
212 if (fs1 < s1) {
213 - s2 -= s1 - fs1;
213 + s2 = XDL_MAX(s2 - (s1 - fs1), 0);
214 s1 = fs1;
215 }
216 }
@@ -232,7 +232,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
232 if (fe1 < 0)
233 fe1 = xe->xdf1.nrec;
234 if (fe1 > e1) {
235 - e2 += fe1 - e1;
235 + e2 = XDL_MIN(e2 + (fe1 - e1), xe->xdf2.nrec);
236 e1 = fe1;
237 }
238