apply.c:update_pre_post_images(): the preimage can be truncated

5166714 (apply: Allow blank context lines to match beyond EOF, 2010-03-06) and then later 0c3ef98 (apply: Allow blank *trailing* context lines to match beyond EOF, 2010-04-08) taught "git apply" to trim new blank lines at the end in the patch text when matching the contents being patched and the preimage recorded in the patch, under --whitespace=fix mode. When a preimage is modified to match the current contents in preparation for such a "fixed" patch application, the context lines in the postimage must be updated to match (otherwise, it would reintroduce whitespace breakages), and update_pre_post_images() function is responsible for doing this. However, this function was not updated to take into account a case where the removal of trailing blank lines reduces the number of lines in the preimage, and triggered an assertion error. The logic to fix the postimage by copying the corrected context lines from the preimage was not prepared to handle this case, either, but it was protected by the assert() and only got exposed when the assertion is corrected. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Oct 12, 2012 at 15:53 UTC 5de7166d46d25fed3b8a181c3842cf4350ecdea4
1 file changed +17 -6
builtin/apply.c
+17 -6
@@ -2086,7 +2086,7 @@ static void update_pre_post_images(struct image *preimage,
2086 char *buf,
2087 size_t len, size_t postlen)
2088 {
2089 - int i, ctx;
2089 + int i, ctx, reduced;
2090 char *new, *old, *fixed;
2091 struct image fixed_preimage;
2092
@@ -2096,8 +2096,10 @@ static void update_pre_post_images(struct image *preimage,
2096 * free "oldlines".
2097 */
2098 prepare_image(&fixed_preimage, buf, len, 1);
2099 - assert(fixed_preimage.nr == preimage->nr);
2100 - for (i = 0; i < preimage->nr; i++)
2099 + assert(postlen
2100 + ? fixed_preimage.nr == preimage->nr
2101 + : fixed_preimage.nr <= preimage->nr);
2102 + for (i = 0; i < fixed_preimage.nr; i++)
2103 fixed_preimage.line[i].flag = preimage->line[i].flag;
2104 free(preimage->line_allocated);
2105 *preimage = fixed_preimage;
@@ -2117,7 +2119,8 @@ static void update_pre_post_images(struct image *preimage,
2119 else
2120 new = old;
2121 fixed = preimage->buf;
2120 - for (i = ctx = 0; i < postimage->nr; i++) {
2122 +
2123 + for (i = reduced = ctx = 0; i < postimage->nr; i++) {
2124 size_t len = postimage->line[i].len;
2125 if (!(postimage->line[i].flag & LINE_COMMON)) {
2126 /* an added line -- no counterparts in preimage */
@@ -2136,8 +2139,15 @@ static void update_pre_post_images(struct image *preimage,
2139 fixed += preimage->line[ctx].len;
2140 ctx++;
2141 }
2139 - if (preimage->nr <= ctx)
2140 - die(_("oops"));
2142 +
2143 + /*
2144 + * preimage is expected to run out, if the caller
2145 + * fixed addition of trailing blank lines.
2146 + */
2147 + if (preimage->nr <= ctx) {
2148 + reduced++;
2149 + continue;
2150 + }
2151
2152 /* and copy it in, while fixing the line length */
2153 len = preimage->line[ctx].len;
@@ -2150,6 +2160,7 @@ static void update_pre_post_images(struct image *preimage,
2160
2161 /* Fix the length of the whole thing */
2162 postimage->len = new - postimage->buf;
2163 + postimage->nr -= reduced;
2164 }
2165
2166 static int match_fragment(struct image *img,