Merge branch 'ps/plug-xdl-merge-leak'
authorJunio C Hamano <gitster@pobox.com>
Fri, 26 Feb 2016 21:37:22 +0000 (13:37 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 26 Feb 2016 21:37:22 +0000 (13:37 -0800)
* ps/plug-xdl-merge-leak:
xdiff/xmerge: fix memory leak in xdl_merge

1  2 
xdiff/xmerge.c
diff --combined xdiff/xmerge.c
index d98f430c912bead3ee5381eafd195dde4d709c47,e272424cfba7b33b821a930a2064d4a3d2e9a6f8..f338ad6c757cda29a052960a504715c062ab5dda
@@@ -109,7 -109,7 +109,7 @@@ static int xdl_merge_cmp_lines(xdfenv_
        return 0;
  }
  
 -static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
 +static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
  {
        xrecord_t **recs;
        int size = 0;
        if (add_nl) {
                i = recs[count - 1]->size;
                if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') {
 +                      if (needs_cr) {
 +                              if (dest)
 +                                      dest[size] = '\r';
 +                              size++;
 +                      }
 +
                        if (dest)
                                dest[size] = '\n';
                        size++;
        return size;
  }
  
 -static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
 +static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
 +{
 +      return xdl_recs_copy_0(0, xe, i, count, needs_cr, add_nl, dest);
 +}
 +
 +static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
 +{
 +      return xdl_recs_copy_0(1, xe, i, count, needs_cr, add_nl, dest);
 +}
 +
 +/*
 + * Returns 1 if the i'th line ends in CR/LF (if it is the last line and
 + * has no eol, the preceding line, if any), 0 if it ends in LF-only, and
 + * -1 if the line ending cannot be determined.
 + */
 +static int is_eol_crlf(xdfile_t *file, int i)
  {
 -      return xdl_recs_copy_0(0, xe, i, count, add_nl, dest);
 +      long size;
 +
 +      if (i < file->nrec - 1)
 +              /* All lines before the last *must* end in LF */
 +              return (size = file->recs[i]->size) > 1 &&
 +                      file->recs[i]->ptr[size - 2] == '\r';
 +      if (!file->nrec)
 +              /* Cannot determine eol style from empty file */
 +              return -1;
 +      if ((size = file->recs[i]->size) &&
 +                      file->recs[i]->ptr[size - 1] == '\n')
 +              /* Last line; ends in LF; Is it CR/LF? */
 +              return size > 1 &&
 +                      file->recs[i]->ptr[size - 2] == '\r';
 +      if (!i)
 +              /* The only line has no eol */
 +              return -1;
 +      /* Determine eol from second-to-last line */
 +      return (size = file->recs[i - 1]->size) > 1 &&
 +              file->recs[i - 1]->ptr[size - 2] == '\r';
  }
  
 -static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
 +static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m)
  {
 -      return xdl_recs_copy_0(1, xe, i, count, add_nl, dest);
 +      int needs_cr;
 +
 +      /* Match post-images' preceding, or first, lines' end-of-line style */
 +      needs_cr = is_eol_crlf(&xe1->xdf2, m->i1 ? m->i1 - 1 : 0);
 +      if (needs_cr)
 +              needs_cr = is_eol_crlf(&xe2->xdf2, m->i2 ? m->i2 - 1 : 0);
 +      /* Look at pre-image's first line, unless we already settled on LF */
 +      if (needs_cr)
 +              needs_cr = is_eol_crlf(&xe1->xdf1, 0);
 +      /* If still undecided, use LF-only */
 +      return needs_cr < 0 ? 0 : needs_cr;
  }
  
  static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
        int marker1_size = (name1 ? strlen(name1) + 1 : 0);
        int marker2_size = (name2 ? strlen(name2) + 1 : 0);
        int marker3_size = (name3 ? strlen(name3) + 1 : 0);
 +      int needs_cr = is_cr_needed(xe1, xe2, m);
  
        if (marker_size <= 0)
                marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
  
        /* Before conflicting part */
 -      size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
 +      size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,
                              dest ? dest + size : NULL);
  
        if (!dest) {
 -              size += marker_size + 1 + marker1_size;
 +              size += marker_size + 1 + needs_cr + marker1_size;
        } else {
                memset(dest + size, '<', marker_size);
                size += marker_size;
                        memcpy(dest + size + 1, name1, marker1_size - 1);
                        size += marker1_size;
                }
 +              if (needs_cr)
 +                      dest[size++] = '\r';
                dest[size++] = '\n';
        }
  
        /* Postimage from side #1 */
 -      size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
 +      size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, 1,
                              dest ? dest + size : NULL);
  
        if (style == XDL_MERGE_DIFF3) {
                /* Shared preimage */
                if (!dest) {
 -                      size += marker_size + 1 + marker3_size;
 +                      size += marker_size + 1 + needs_cr + marker3_size;
                } else {
                        memset(dest + size, '|', marker_size);
                        size += marker_size;
                                memcpy(dest + size + 1, name3, marker3_size - 1);
                                size += marker3_size;
                        }
 +                      if (needs_cr)
 +                              dest[size++] = '\r';
                        dest[size++] = '\n';
                }
 -              size += xdl_orig_copy(xe1, m->i0, m->chg0, 1,
 +              size += xdl_orig_copy(xe1, m->i0, m->chg0, needs_cr, 1,
                                      dest ? dest + size : NULL);
        }
  
        if (!dest) {
 -              size += marker_size + 1;
 +              size += marker_size + 1 + needs_cr;
        } else {
                memset(dest + size, '=', marker_size);
                size += marker_size;
 +              if (needs_cr)
 +                      dest[size++] = '\r';
                dest[size++] = '\n';
        }
  
        /* Postimage from side #2 */
 -      size += xdl_recs_copy(xe2, m->i2, m->chg2, 1,
 +      size += xdl_recs_copy(xe2, m->i2, m->chg2, needs_cr, 1,
                              dest ? dest + size : NULL);
        if (!dest) {
 -              size += marker_size + 1 + marker2_size;
 +              size += marker_size + 1 + needs_cr + marker2_size;
        } else {
                memset(dest + size, '>', marker_size);
                size += marker_size;
                        memcpy(dest + size + 1, name2, marker2_size - 1);
                        size += marker2_size;
                }
 +              if (needs_cr)
 +                      dest[size++] = '\r';
                dest[size++] = '\n';
        }
        return size;
@@@ -300,24 -241,21 +300,24 @@@ static int xdl_fill_merge_buffer(xdfenv
                                                  marker_size);
                else if (m->mode & 3) {
                        /* Before conflicting part */
 -                      size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
 +                      size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,
                                              dest ? dest + size : NULL);
                        /* Postimage from side #1 */
 -                      if (m->mode & 1)
 -                              size += xdl_recs_copy(xe1, m->i1, m->chg1, (m->mode & 2),
 +                      if (m->mode & 1) {
 +                              int needs_cr = is_cr_needed(xe1, xe2, m);
 +
 +                              size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, (m->mode & 2),
                                                      dest ? dest + size : NULL);
 +                      }
                        /* Postimage from side #2 */
                        if (m->mode & 2)
 -                              size += xdl_recs_copy(xe2, m->i2, m->chg2, 0,
 +                              size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, 0,
                                                      dest ? dest + size : NULL);
                } else
                        continue;
                i = m->i1 + m->chg1;
        }
 -      size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0,
 +      size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, 0,
                              dest ? dest + size : NULL);
        return size;
  }
@@@ -641,8 -579,11 +641,11 @@@ int xdl_merge(mmfile_t *orig, mmfile_t 
        result->ptr = NULL;
        result->size = 0;
  
-       if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0 ||
-                       xdl_do_diff(orig, mf2, xpp, &xe2) < 0) {
+       if (xdl_do_diff(orig, mf1, xpp, &xe1) < 0) {
+               return -1;
+       }
+       if (xdl_do_diff(orig, mf2, xpp, &xe2) < 0) {
+               xdl_free_env(&xe1);
                return -1;
        }
        if (xdl_change_compact(&xe1.xdf1, &xe1.xdf2, xpp->flags) < 0 ||
        if (xdl_change_compact(&xe2.xdf1, &xe2.xdf2, xpp->flags) < 0 ||
            xdl_change_compact(&xe2.xdf2, &xe2.xdf1, xpp->flags) < 0 ||
            xdl_build_script(&xe2, &xscr2) < 0) {
+               xdl_free_script(xscr1);
+               xdl_free_env(&xe1);
                xdl_free_env(&xe2);
                return -1;
        }