xdiff: clamp function context indices in post-image
authorJeff King <peff@peff.net>
Tue, 23 Jul 2019 19:27:05 +0000 (15:27 -0400)
committerJunio C Hamano <gitster@pobox.com>
Tue, 23 Jul 2019 21:26:13 +0000 (14:26 -0700)
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>
t/t4015-diff-whitespace.sh
xdiff/xemit.c
index a9fb226c5ad566095163c5141a4ca591f2aeacb1..04d1bbecbe8adcc67e26f4c9ad6741604b22965c 100755 (executable)
@@ -1897,4 +1897,26 @@ test_expect_success 'compare whitespace delta incompatible with other space opti
        test_i18ngrep allow-indentation-change err
 '
 
+# Note that the "6" in the expected hunk header below is funny, since we only
+# show 5 lines (the missing one was blank and thus ignored). This is how
+# --ignore-blank-lines behaves even without --function-context, and this test
+# is just checking the interaction of the two features. Don't take it as an
+# endorsement of that output.
+test_expect_success 'combine --ignore-blank-lines with --function-context' '
+       test_write_lines 1 "" 2 3 4 5 >a &&
+       test_write_lines 1    2 3 4   >b &&
+       test_must_fail git diff --no-index \
+               --ignore-blank-lines --function-context a b >actual.raw &&
+       sed -n "/@@/,\$p" <actual.raw >actual &&
+       cat <<-\EOF >expect &&
+       @@ -1,6 +1,4 @@
+        1
+        2
+        3
+        4
+       -5
+       EOF
+       test_cmp expect actual
+'
+
 test_done
index 7778dc2b190f84fe2ab1e1539756a7e1f4254c3b..30713ae9a98ecfc9f764120d3a1d18b5a8ee11bf 100644 (file)
@@ -210,7 +210,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
                        if (fs1 < 0)
                                fs1 = 0;
                        if (fs1 < s1) {
-                               s2 -= s1 - fs1;
+                               s2 = XDL_MAX(s2 - (s1 - fs1), 0);
                                s1 = fs1;
                        }
                }
@@ -232,7 +232,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
                        if (fe1 < 0)
                                fe1 = xe->xdf1.nrec;
                        if (fe1 > e1) {
-                               e2 += fe1 - e1;
+                               e2 = XDL_MIN(e2 + (fe1 - e1), xe->xdf2.nrec);
                                e1 = fe1;
                        }