apply --whitespace=fix: avoid running over the postimage buffer

Originally update-pre-post-images could assume that any whitespace fixing will make the result only shorter by unexpanding runs of leading SPs into HTs and removing trailing whitespaces at the end of lines. Updating the post-image we read from the patch to match the actual result can be performed in-place under this assumption. These days, however, we have tab-in-indent (aka Python) rule whose result can be longer than the original, and we do need to allocate a larger buffer than the input and replace the result. Fortunately the support for lengthening rewrite was already added when we began supporting "match while ignoring whitespace differences" mode in 86c91f91794c (git apply: option to ignore whitespace differences, 2009-08-04). We only need to correctly count the number of bytes necessary to hold the updated result and tell the function to allocate a new buffer. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Mar 22, 2013 at 11:10 UTC 250b3c6c992b3cb04e756eb33bed99442fc55193
4 files changed +39 -9
builtin/apply.c
+10 -6
@@ -2113,10 +2113,10 @@ static void update_pre_post_images(struct image *preimage,
2113
2114 /*
2115 * Adjust the common context lines in postimage. This can be
2116 - * done in-place when we are just doing whitespace fixing,
2117 - * which does not make the string grow, but needs a new buffer
2118 - * when ignoring whitespace causes the update, since in this case
2119 - * we could have e.g. tabs converted to multiple spaces.
2116 + * done in-place when we are shrinking it with whitespace
2117 + * fixing, but needs a new buffer when ignoring whitespace or
2118 + * expanding leading tabs to spaces.
2119 + *
2120 * We trust the caller to tell us if the update can be done
2121 * in place (postlen==0) or not.
2122 */
@@ -2172,7 +2172,7 @@ static int match_fragment(struct image *img,
2172 int i;
2173 char *fixed_buf, *buf, *orig, *target;
2174 struct strbuf fixed;
2175 - size_t fixed_len;
2175 + size_t fixed_len, postlen;
2176 int preimage_limit;
2177
2178 if (preimage->nr + try_lno <= img->nr) {
@@ -2322,6 +2322,7 @@ static int match_fragment(struct image *img,
2322 strbuf_init(&fixed, preimage->len + 1);
2323 orig = preimage->buf;
2324 target = img->buf + try;
2325 + postlen = 0;
2326 for (i = 0; i < preimage_limit; i++) {
2327 size_t oldlen = preimage->line[i].len;
2328 size_t tgtlen = img->line[try_lno + i].len;
@@ -2349,6 +2350,7 @@ static int match_fragment(struct image *img,
2350 match = (tgtfix.len == fixed.len - fixstart &&
2351 !memcmp(tgtfix.buf, fixed.buf + fixstart,
2352 fixed.len - fixstart));
2353 + postlen += tgtfix.len;
2354
2355 strbuf_release(&tgtfix);
2356 if (!match)
@@ -2386,8 +2388,10 @@ static int match_fragment(struct image *img,
2388 * hunk match. Update the context lines in the postimage.
2389 */
2390 fixed_buf = strbuf_detach(&fixed, &fixed_len);
2391 + if (postlen < postimage->len)
2392 + postlen = 0;
2393 update_pre_post_images(preimage, postimage,
2390 - fixed_buf, fixed_len, 0);
2394 + fixed_buf, fixed_len, postlen);
2395 return 1;
2396
2397 unmatch_exit:
t/t4124-apply-ws-rule.sh
+26
@@ -486,4 +486,30 @@ test_expect_success 'same, but with CR-LF line endings && cr-at-eol unset' '
486 test_cmp one expect
487 '
488
489 +test_expect_success 'whitespace=fix to expand' '
490 + qz_to_tab_space >preimage <<-\EOF &&
491 + QQa
492 + QQb
493 + QQc
494 + ZZZZZZZZZZZZZZZZd
495 + QQe
496 + QQf
497 + QQg
498 + EOF
499 + qz_to_tab_space >patch <<-\EOF &&
500 + diff --git a/preimage b/preimage
501 + --- a/preimage
502 + +++ b/preimage
503 + @@ -1,7 +1,6 @@
504 + QQa
505 + QQb
506 + QQc
507 + -QQd
508 + QQe
509 + QQf
510 + QQg
511 + EOF
512 + git -c core.whitespace=tab-in-indent apply --whitespace=fix patch
513 +'
514 +
515 test_done
t/t4150-am.sh
+1 -1
@@ -17,7 +17,7 @@ test_expect_success 'setup: messages' '
17 vero eos et accusam et justo duo dolores et ea rebum.
18
19 EOF
20 - q_to_tab <<-\EOF >>msg &&
20 + qz_to_tab_space <<-\EOF >>msg &&
21 QDuis autem vel eum iriure dolor in hendrerit in vulputate velit
22 Qesse molestie consequat, vel illum dolore eu feugiat nulla facilisis
23 Qat vero eros et accumsan et iusto odio dignissim qui blandit
t/test-lib-functions.sh
+2 -2
@@ -87,8 +87,8 @@ q_to_cr () {
87 tr Q '\015'
88 }
89
90 -q_to_tab () {
91 - tr Q '\011'
90 +qz_to_tab_space () {
91 + tr QZ '\011\040'
92 }
93
94 append_cr () {