Re: [BUGREPORT] git diff-tree --cc SEGFAUTs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jan 3, 2025 at 7:32 PM Jeff King <peff@xxxxxxxx> wrote:
>
> On Fri, Jan 03, 2025 at 06:55:18PM -0800, Junio C Hamano wrote:
>
> > Jeff King <peff@xxxxxxxx> writes:
> >
> > > ... OTOH it is not really
> > > solving the more fundamental problem, which is that p->parent[i].path is
> > > only sometimes useful (we do not fill it in if it would just be the same
> > > as p->path, so the patch only changes it from uninitialized memory into
> > > an empty strbuf).
> > >
> > > And that is probably not something we want to change, as allocating
> > > duplicates of each path may be expensive.
> >
> > Nicely said.  I reached the same conclusion after looking at the
> > existing code, even though I have to admit that I am not a huge fan
> > of the more recent part of combine-diff.c and its data structures.
>
> I poked at this a little bit more, so here are a few tidbits:
>
>   - the patch I showed earlier is not sufficient! There are lots of
>     other spots that create combine_diff_path structs but don't bother
>     to put anything in the parent paths at all. It works now because
>     they also don't set a status that triggers filename_changed(). But
>     what I showed earlier was wrong, because it was assuming in the
>     cleanup functions that the strbufs were always initialized.
>
>   - there's really no need for a strbuf at all here. It is always
>     uninitialized/empty, or contains a direct copy of a path string. So
>     a raw pointer with xstrdup() is plenty. And then we can use NULL to
>     mean "it was not set".
>
>     Which would Just Work for all those other spots if they bothered to
>     zero the memory they allocated, but they don't. So we have to update
>     them to set it to NULL anyway. That patch is below.
>
>   - it is not at all clear to me that we need to be allocating at all.
>     We always copy a string from the diff_queue. Do our
>     combine_diff_path structs persist beyond then? I'm not sure. It is
>     probably asking for trouble to just point to them directly without
>     copying, as it creates a dependency (that even if it is not needed
>     now, is a trap for somebody later). But it would drop some
>     allocation/cleanup code, and we could just have p->parent[i].path
>     fall back to p->path naturally.
>
> diff --git a/combine-diff.c b/combine-diff.c
> index 641bc92dbd..0d9d344c4e 100644
> --- a/combine-diff.c
> +++ b/combine-diff.c
> @@ -66,13 +66,9 @@ static struct combine_diff_path *intersect_paths(
>                         oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
>                         p->parent[n].mode = q->queue[i]->one->mode;
>                         p->parent[n].status = q->queue[i]->status;
> -
> -                       if (combined_all_paths &&
> -                           filename_changed(p->parent[n].status)) {
> -                               strbuf_init(&p->parent[n].path, 0);
> -                               strbuf_addstr(&p->parent[n].path,
> -                                             q->queue[i]->one->path);
> -                       }
> +                       p->parent[n].path = combined_all_paths &&
> +                                           filename_changed(p->parent[n].status) ?
> +                                           xstrdup(q->queue[i]->one->path) : NULL;
>                         *tail = p;
>                         tail = &p->next;
>                 }
> @@ -92,9 +88,7 @@ static struct combine_diff_path *intersect_paths(
>                         /* p->path not in q->queue[]; drop it */
>                         *tail = p->next;
>                         for (j = 0; j < num_parent; j++)
> -                               if (combined_all_paths &&
> -                                   filename_changed(p->parent[j].status))
> -                                       strbuf_release(&p->parent[j].path);
> +                               free(p->parent[j].path);
>                         free(p);
>                         continue;
>                 }
> @@ -108,10 +102,9 @@ static struct combine_diff_path *intersect_paths(
>                 oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
>                 p->parent[n].mode = q->queue[i]->one->mode;
>                 p->parent[n].status = q->queue[i]->status;
> -               if (combined_all_paths &&
> -                   filename_changed(p->parent[n].status))
> -                       strbuf_addstr(&p->parent[n].path,
> -                                     q->queue[i]->one->path);
> +               p->parent[n].path = combined_all_paths &&
> +                                   filename_changed(p->parent[n].status) ?
> +                                   xstrdup(q->queue[i]->one->path) : NULL;
>
>                 tail = &p->next;
>                 i++;
> @@ -996,8 +989,9 @@ static void show_combined_header(struct combine_diff_path *elem,
>
>         if (rev->combined_all_paths) {
>                 for (i = 0; i < num_parent; i++) {
> -                       char *path = filename_changed(elem->parent[i].status)
> -                               ? elem->parent[i].path.buf : elem->path;
> +                       const char *path = elem->parent[i].path ?
> +                                          elem->parent[i].path :
> +                                          elem->path;
>                         if (elem->parent[i].status == DIFF_STATUS_ADDED)
>                                 dump_quoted_path("--- ", "", "/dev/null",
>                                                  line_prefix, c_meta, c_reset);
> @@ -1278,12 +1272,10 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
>
>         for (i = 0; i < num_parent; i++)
>                 if (rev->combined_all_paths) {
> -                       if (filename_changed(p->parent[i].status))
> -                               write_name_quoted(p->parent[i].path.buf, stdout,
> -                                                 inter_name_termination);
> -                       else
> -                               write_name_quoted(p->path, stdout,
> -                                                 inter_name_termination);
> +                       const char *path = p->parent[i].path ?
> +                                          p->parent[i].path :
> +                                          p->path;
> +                       write_name_quoted(path, stdout, inter_name_termination);
>                 }
>         write_name_quoted(p->path, stdout, line_termination);
>  }
> @@ -1645,9 +1637,7 @@ void diff_tree_combined(const struct object_id *oid,
>                 struct combine_diff_path *tmp = paths;
>                 paths = paths->next;
>                 for (i = 0; i < num_parent; i++)
> -                       if (rev->combined_all_paths &&
> -                           filename_changed(tmp->parent[i].status))
> -                               strbuf_release(&tmp->parent[i].path);
> +                       free(tmp->parent[i].path);
>                 free(tmp);
>         }
>
> diff --git a/diff-lib.c b/diff-lib.c
> index c6d3bc4d37..88a5aed736 100644
> --- a/diff-lib.c
> +++ b/diff-lib.c
> @@ -417,9 +417,11 @@ static int show_modified(struct rev_info *revs,
>                 memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
>                 p->parent[0].status = DIFF_STATUS_MODIFIED;
>                 p->parent[0].mode = new_entry->ce_mode;
> +               p->parent[0].path = NULL;
>                 oidcpy(&p->parent[0].oid, &new_entry->oid);
>                 p->parent[1].status = DIFF_STATUS_MODIFIED;
>                 p->parent[1].mode = old_entry->ce_mode;
> +               p->parent[1].path = NULL;
>                 oidcpy(&p->parent[1].oid, &old_entry->oid);
>                 show_combined_diff(p, 2, revs);
>                 free(p);
> diff --git a/diff.h b/diff.h
> index 6e6007c17b..3157faeabb 100644
> --- a/diff.h
> +++ b/diff.h
> @@ -480,7 +480,7 @@ struct combine_diff_path {
>                 char status;
>                 unsigned int mode;
>                 struct object_id oid;
> -               struct strbuf path;
> +               char *path;
>         } parent[FLEX_ARRAY];
>  };
>  #define combine_diff_path_size(n, l) \
> diff --git a/tree-diff.c b/tree-diff.c
> index d9237ffd9b..57af377c2b 100644
> --- a/tree-diff.c
> +++ b/tree-diff.c
> @@ -272,6 +272,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
>                         }
>
>                         p->parent[i].mode = mode_i;
> +                       p->parent[i].path = NULL;
>                         oidcpy(&p->parent[i].oid, oid_i);
>                 }

The above LGTM and hopefully it can be accepted.

With that change I can revert my trace_printfs of combine_diff_path
back to something simple:
```
$ git diff HEAD^
diff --git a/combine-diff.c b/combine-diff.c
index 5e0b7919bc..4764383f20 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -1593,8 +1593,8 @@ void diff_tree_combined(const struct object_id *oid,
        for (num_paths = 0, p = paths; p; p = p->next) {
                trace_printf("Wink diff_tree_combined: num_paths=%d
&p=%p mode=%0x, oid=%s path=%s\n", num_paths, p, p->mode,
oid_to_hex(&p->oid), p->path);
                for (i = 0; i < num_parent; i++) {
-                       trace_printf("Wink diff_tree_combined:
&p->parent[%d]=%p status=%c mode=%x oid=%s path.buf=%p contents
path.buf=%s\n",
-                                i, &p->parent[i],
p->parent[i].status, p->parent[i].mode, oid_to_hex(&p->parent[i].oid),
p->parent[i].path.buf, p->parent[i].path.buf);
+                       trace_printf("Wink diff_tree_combined:
&p->parent[%d]=%p status=%c mode=%x oid=%s path=%s\n",
+                                i, &p->parent[i],
p->parent[i].status, p->parent[i].mode, oid_to_hex(&p->parent[i].oid),
p->parent[i].path);
                }
                num_paths++;
        }
```

And the output doesn't SEGFAULT :)
```
$ GIT_TRACE=1 ./git diff-tree --cc 6f8ae955bda8ad246cc1f5f7a15f1c3b1c04696a
10:06:11.716284 git.c:476               trace: built-in: git diff-tree
--cc 6f8ae955bda8ad246cc1f5f7a15f1c3b1c04696a
6f8ae955bda8ad246cc1f5f7a15f1c3b1c04696a
10:06:11.718102 combine-diff.c:1592     Wink diff_tree_combined: find
number of surviving paths num_parent=2
10:06:11.718108 combine-diff.c:1594     Wink diff_tree_combined:
num_paths=0 &p=0x643ac70f7ef0 mode=81a4,
oid=0f41b2fd4a6b679a1cfcaa9a584c382068146212 path=refs.c
10:06:11.718112 combine-diff.c:1596     Wink diff_tree_combined:
&p->parent[0]=0x643ac70f7f28 status=M mode=81a4
oid=7dd5e9fa3323111f06303674b213ae24ed2d04b6 path=(null)
10:06:11.718116 combine-diff.c:1596     Wink diff_tree_combined:
&p->parent[1]=0x643ac70f7f60 status=M mode=81a4
oid=c55583986940d8ef1e1c839364c03cd92d4f7114 path=(null)
10:06:11.718120 combine-diff.c:1594     Wink diff_tree_combined:
num_paths=1 &p=0x643ac70f7fb0 mode=81a4,
oid=a0cdd99250e8286b55808b697b0a94afac5d8319 path=refs.h
10:06:11.718123 combine-diff.c:1596     Wink diff_tree_combined:
&p->parent[0]=0x643ac70f7fe8 status=M mode=81a4
oid=09be47afbee51e99f4ae49588cd65596ccfcb07e path=(null)
10:06:11.718126 combine-diff.c:1596     Wink diff_tree_combined:
&p->parent[1]=0x643ac70f8020 status=M mode=81a4
oid=b0dfc65ed2e59c4b66967840339f81e7746a96d3 path=(null)
10:06:11.718129 combine-diff.c:1594     Wink diff_tree_combined:
num_paths=2 &p=0x643ac70f8900 mode=81a4,
oid=5cfb8b7ca8678e171b8e8a7ad6daf1af74a81b59 path=refs/files-backend.c
10:06:11.718132 combine-diff.c:1596     Wink diff_tree_combined:
&p->parent[0]=0x643ac70f8938 status=M mode=81a4
oid=467fe347fa7e7d82ed7a2836e43ea749bb90ad7d path=(null)
10:06:11.718135 combine-diff.c:1596     Wink diff_tree_combined:
&p->parent[1]=0x643ac70f8970 status=M mode=81a4
oid=8953d1c6d37b13b0db701888b3db92fd87a68aaa path=(null)
10:06:11.718138 combine-diff.c:1594     Wink diff_tree_combined:
num_paths=3 &p=0x643ac70f89d0 mode=81a4,
oid=16550862d3ebe3b357c52254088b143c7ba000d6 path=refs/refs-internal.h
10:06:11.718142 combine-diff.c:1596     Wink diff_tree_combined:
&p->parent[0]=0x643ac70f8a08 status=M mode=81a4
oid=66e66e0fc1e812ebebd1d4b0119899c84bf1c0ae path=(null)
10:06:11.718162 combine-diff.c:1596     Wink diff_tree_combined:
&p->parent[1]=0x643ac70f8a40 status=M mode=81a4
oid=79b287c5ec5c7d8f759869cf93cda405640186dc path=(null)
10:06:11.718181 combine-diff.c:1594     Wink diff_tree_combined:
num_paths=4 &p=0x643ac70f8aa0 mode=81a4,
oid=00d95a9a2f42ce74c5cb4a42175b0953287851a6
path=refs/reftable-backend.c
10:06:11.718184 combine-diff.c:1596     Wink diff_tree_combined:
&p->parent[0]=0x643ac70f8ad8 status=M mode=81a4
oid=8a2a5b847c3d86332e319da69bfb5c8a56a10e86 path=(null)
10:06:11.718188 combine-diff.c:1596     Wink diff_tree_combined:
&p->parent[1]=0x643ac70f8b10 status=M mode=81a4
oid=bec5962debea7b62572d08f6fa8fd38ab4cd8af6 path=(null)
10:06:11.718192 combine-diff.c:1601     Wink diff_tree_combined: found
5 surviving paths
diff --cc refs/files-backend.c
index 467fe347fa,8953d1c6d3..5cfb8b7ca8
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@@ -2533,9 -2539,15 +2543,15 @@@ static int check_old_oid(struct ref_upd
                            oid_to_hex(oid),
                            oid_to_hex(&update->old_oid));

 -      return -1;
 +      return ret;
  }

+ struct files_transaction_backend_data {
+       struct ref_transaction *packed_transaction;
+       int packed_refs_locked;
+       struct strmap ref_locks;
+ };
+
  /*
   * Prepare for carrying out update:
   * - Lock the reference referred to by update.
```





[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux