]> git.ipfire.org Git - thirdparty/git.git/blobdiff - diff.c
diff --color-moved-ws: fix another memory leak
[thirdparty/git.git] / diff.c
diff --git a/diff.c b/diff.c
index 0549fc6e2cf3e0ea2610921be5ee0bdf990f2670..e0ebddfac9f024945844a77c971ab9a6596e3fb5 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -776,7 +776,6 @@ struct moved_entry {
        struct hashmap_entry ent;
        const struct emitted_diff_symbol *es;
        struct moved_entry *next_line;
-       struct ws_delta *wsd;
 };
 
 /**
@@ -793,6 +792,17 @@ struct ws_delta {
 };
 #define WS_DELTA_INIT { NULL, 0 }
 
+struct moved_block {
+       struct moved_entry *match;
+       struct ws_delta wsd;
+};
+
+static void moved_block_clear(struct moved_block *b)
+{
+       FREE_AND_NULL(b->wsd.string);
+       b->match = NULL;
+}
+
 static int compute_ws_delta(const struct emitted_diff_symbol *a,
                             const struct emitted_diff_symbol *b,
                             struct ws_delta *out)
@@ -801,16 +811,19 @@ static int compute_ws_delta(const struct emitted_diff_symbol *a,
        const struct emitted_diff_symbol *shorter = a->len > b->len ? b : a;
        int d = longer->len - shorter->len;
 
+       if (strncmp(longer->line + d, shorter->line, shorter->len))
+               return 0;
+
        out->string = xmemdupz(longer->line, d);
        out->current_longer = (a == longer);
 
-       return !strncmp(longer->line + d, shorter->line, shorter->len);
+       return 1;
 }
 
 static int cmp_in_block_with_wsd(const struct diff_options *o,
                                 const struct moved_entry *cur,
                                 const struct moved_entry *match,
-                                struct moved_entry *pmb,
+                                struct moved_block *pmb,
                                 int n)
 {
        struct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];
@@ -830,16 +843,15 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
        if (strcmp(a, b))
                return 1;
 
-       if (!pmb->wsd)
+       if (!pmb->wsd.string)
                /*
-                * No white space delta was carried forward? This can happen
-                * when we exit early in this function and do not carry
-                * forward ws.
+                * The white space delta is not active? This can happen
+                * when we exit early in this function.
                 */
                return 1;
 
        /*
-        * The indent changes of the block are known and carried forward in
+        * The indent changes of the block are known and stored in
         * pmb->wsd; however we need to check if the indent changes of the
         * current line are still the same as before.
         *
@@ -847,8 +859,8 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
         * one of them for the white spaces, depending which was longer.
         */
 
-       wslen = strlen(pmb->wsd->string);
-       if (pmb->wsd->current_longer) {
+       wslen = strlen(pmb->wsd.string);
+       if (pmb->wsd.current_longer) {
                c += wslen;
                cl -= wslen;
        } else {
@@ -856,7 +868,7 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
                al -= wslen;
        }
 
-       if (strcmp(a, c))
+       if (al != cl || memcmp(a, c, al))
                return 1;
 
        return 0;
@@ -898,7 +910,6 @@ static struct moved_entry *prepare_entry(struct diff_options *o,
        ret->ent.hash = xdiff_hash_string(l->line, l->len, flags);
        ret->es = l;
        ret->next_line = NULL;
-       ret->wsd = NULL;
 
        return ret;
 }
@@ -938,18 +949,18 @@ static void add_lines_to_move_detection(struct diff_options *o,
 static void pmb_advance_or_null(struct diff_options *o,
                                struct moved_entry *match,
                                struct hashmap *hm,
-                               struct moved_entry **pmb,
+                               struct moved_block *pmb,
                                int pmb_nr)
 {
        int i;
        for (i = 0; i < pmb_nr; i++) {
-               struct moved_entry *prev = pmb[i];
+               struct moved_entry *prev = pmb[i].match;
                struct moved_entry *cur = (prev && prev->next_line) ?
                                prev->next_line : NULL;
                if (cur && !hm->cmpfn(o, cur, match, NULL)) {
-                       pmb[i] = cur;
+                       pmb[i].match = cur;
                } else {
-                       pmb[i] = NULL;
+                       pmb[i].match = NULL;
                }
        }
 }
@@ -957,7 +968,7 @@ static void pmb_advance_or_null(struct diff_options *o,
 static void pmb_advance_or_null_multi_match(struct diff_options *o,
                                            struct moved_entry *match,
                                            struct hashmap *hm,
-                                           struct moved_entry **pmb,
+                                           struct moved_block *pmb,
                                            int pmb_nr, int n)
 {
        int i;
@@ -965,48 +976,47 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,
 
        for (; match; match = hashmap_get_next(hm, match)) {
                for (i = 0; i < pmb_nr; i++) {
-                       struct moved_entry *prev = pmb[i];
+                       struct moved_entry *prev = pmb[i].match;
                        struct moved_entry *cur = (prev && prev->next_line) ?
                                        prev->next_line : NULL;
                        if (!cur)
                                continue;
-                       if (!cmp_in_block_with_wsd(o, cur, match, pmb[i], n))
+                       if (!cmp_in_block_with_wsd(o, cur, match, &pmb[i], n))
                                got_match[i] |= 1;
                }
        }
 
        for (i = 0; i < pmb_nr; i++) {
                if (got_match[i]) {
-                       /* Carry the white space delta forward */
-                       pmb[i]->next_line->wsd = pmb[i]->wsd;
-                       pmb[i] = pmb[i]->next_line;
-               } else
-                       pmb[i] = NULL;
+                       /* Advance to the next line */
+                       pmb[i].match = pmb[i].match->next_line;
+               } else {
+                       moved_block_clear(&pmb[i]);
+               }
        }
+
+       free(got_match);
 }
 
-static int shrink_potential_moved_blocks(struct moved_entry **pmb,
+static int shrink_potential_moved_blocks(struct moved_block *pmb,
                                         int pmb_nr)
 {
        int lp, rp;
 
        /* Shrink the set of potential block to the remaining running */
        for (lp = 0, rp = pmb_nr - 1; lp <= rp;) {
-               while (lp < pmb_nr && pmb[lp])
+               while (lp < pmb_nr && pmb[lp].match)
                        lp++;
                /* lp points at the first NULL now */
 
-               while (rp > -1 && !pmb[rp])
+               while (rp > -1 && !pmb[rp].match)
                        rp--;
                /* rp points at the last non-NULL */
 
                if (lp < pmb_nr && rp > -1 && lp < rp) {
                        pmb[lp] = pmb[rp];
-                       if (pmb[rp]->wsd) {
-                               free(pmb[rp]->wsd->string);
-                               FREE_AND_NULL(pmb[rp]->wsd);
-                       }
-                       pmb[rp] = NULL;
+                       pmb[rp].match = NULL;
+                       pmb[rp].wsd.string = NULL;
                        rp--;
                        lp++;
                }
@@ -1053,7 +1063,7 @@ static void mark_color_as_moved(struct diff_options *o,
                                struct hashmap *add_lines,
                                struct hashmap *del_lines)
 {
-       struct moved_entry **pmb = NULL; /* potentially moved blocks */
+       struct moved_block *pmb = NULL; /* potentially moved blocks */
        int pmb_nr = 0, pmb_alloc = 0;
        int n, flipped_block = 1, block_length = 0;
 
@@ -1082,7 +1092,11 @@ static void mark_color_as_moved(struct diff_options *o,
                }
 
                if (!match) {
+                       int i;
+
                        adjust_last_block(o, n, block_length);
+                       for(i = 0; i < pmb_nr; i++)
+                               moved_block_clear(&pmb[i]);
                        pmb_nr = 0;
                        block_length = 0;
                        continue;
@@ -1110,14 +1124,12 @@ static void mark_color_as_moved(struct diff_options *o,
                                ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);
                                if (o->color_moved_ws_handling &
                                    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {
-                                       struct ws_delta *wsd = xmalloc(sizeof(*match->wsd));
-                                       if (compute_ws_delta(l, match->es, wsd)) {
-                                               match->wsd = wsd;
-                                               pmb[pmb_nr++] = match;
-                                       } else
-                                               free(wsd);
+                                       if (compute_ws_delta(l, match->es,
+                                                            &pmb[pmb_nr].wsd))
+                                               pmb[pmb_nr++].match = match;
                                } else {
-                                       pmb[pmb_nr++] = match;
+                                       pmb[pmb_nr].wsd.string = NULL;
+                                       pmb[pmb_nr++].match = match;
                                }
                        }
 
@@ -1134,6 +1146,8 @@ static void mark_color_as_moved(struct diff_options *o,
        }
        adjust_last_block(o, n, block_length);
 
+       for(n = 0; n < pmb_nr; n++)
+               moved_block_clear(&pmb[n]);
        free(pmb);
 }
 
@@ -2948,16 +2962,11 @@ static void show_dirstat(struct diff_options *options)
                struct diff_filepair *p = q->queue[i];
                const char *name;
                unsigned long copied, added, damage;
-               int content_changed;
 
                name = p->two->path ? p->two->path : p->one->path;
 
-               if (p->one->oid_valid && p->two->oid_valid)
-                       content_changed = oidcmp(&p->one->oid, &p->two->oid);
-               else
-                       content_changed = 1;
-
-               if (!content_changed) {
+               if (p->one->oid_valid && p->two->oid_valid &&
+                   oideq(&p->one->oid, &p->two->oid)) {
                        /*
                         * The SHA1 has not changed, so pre-/post-content is
                         * identical. We can therefore skip looking at the
@@ -3004,7 +3013,7 @@ static void show_dirstat(struct diff_options *options)
                 * made to the preimage.
                 * If the resulting damage is zero, we know that
                 * diffcore_count_changes() considers the two entries to
-                * be identical, but since content_changed is true, we
+                * be identical, but since the oid changed, we
                 * know that there must have been _some_ kind of change,
                 * so we force all entries to have damage > 0.
                 */
@@ -3419,7 +3428,7 @@ static void builtin_diff(const char *name_a,
                if (!one->data && !two->data &&
                    S_ISREG(one->mode) && S_ISREG(two->mode) &&
                    !o->flags.binary) {
-                       if (!oidcmp(&one->oid, &two->oid)) {
+                       if (oideq(&one->oid, &two->oid)) {
                                if (must_show_header)
                                        emit_diff_symbol(o, DIFF_SYMBOL_HEADER,
                                                         header.buf, header.len,
@@ -3584,7 +3593,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                return;
        }
 
-       same_contents = !oidcmp(&one->oid, &two->oid);
+       same_contents = oideq(&one->oid, &two->oid);
 
        if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
                data->is_binary = 1;
@@ -3780,7 +3789,7 @@ static int reuse_worktree_file(const char *name, const struct object_id *oid, in
         * This is not the sha1 we are looking for, or
         * unreusable because it is not a regular file.
         */
-       if (oidcmp(oid, &ce->oid) || !S_ISREG(ce->ce_mode))
+       if (!oideq(oid, &ce->oid) || !S_ISREG(ce->ce_mode))
                return 0;
 
        /*
@@ -4185,7 +4194,7 @@ static void fill_metainfo(struct strbuf *msg,
        default:
                *must_show_header = 0;
        }
-       if (one && two && oidcmp(&one->oid, &two->oid)) {
+       if (one && two && !oideq(&one->oid, &two->oid)) {
                const unsigned hexsz = the_hash_algo->hexsz;
                int abbrev = o->flags.full_index ? hexsz : DEFAULT_ABBREV;
 
@@ -5347,7 +5356,7 @@ int diff_unmodified_pair(struct diff_filepair *p)
         * dealing with a change.
         */
        if (one->oid_valid && two->oid_valid &&
-           !oidcmp(&one->oid, &two->oid) &&
+           oideq(&one->oid, &two->oid) &&
            !one->dirty_submodule && !two->dirty_submodule)
                return 1; /* no change */
        if (!one->oid_valid && !two->oid_valid)
@@ -5481,7 +5490,7 @@ static void diff_resolve_rename_copy(void)
                        else
                                p->status = DIFF_STATUS_RENAMED;
                }
-               else if (oidcmp(&p->one->oid, &p->two->oid) ||
+               else if (!oideq(&p->one->oid, &p->two->oid) ||
                         p->one->mode != p->two->mode ||
                         p->one->dirty_submodule ||
                         p->two->dirty_submodule ||