]> git.ipfire.org Git - thirdparty/git.git/commitdiff
unpack-trees: watch for out-of-range index position
authorEmily Shaffer <emilyshaffer@google.com>
Wed, 8 Jan 2020 02:31:27 +0000 (18:31 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 8 Jan 2020 17:31:18 +0000 (09:31 -0800)
It's possible in a case where the index file contains a tree extension
but no blobs within that tree exist for index_pos_by_traverse_info() to
segfault. If the name_entry passed into index_pos_by_traverse_info() has
no blobs inside, AND is alphabetically later than all blobs currently in
the index file, index_pos_by_traverse_info() will segfault. For example,
an index file which looks something like this:

  aaa#0
  bbb/aaa#0
  [Extensions]
  TREE: zzz

In this example, 'index_name_pos(..., "zzz/", ...)' will return '-4',
indicating that "zzz/" could be inserted at position 3. However, when
the checks which ensure that the insertion position of "zzz/" look for a
blob at that position beginning with "zzz/", the index cache is accessed
out of range, causing a segfault.

This kind of index state is not typically generated during user
operations, and is in fact an edge case of the state being checked for
in the conditional where it was added. However, since the entry for the
BUG() line is ambiguous, tell some additional context to help Git
developers debug the failure later. When we know the name of the dir we
were trying to look up, it becomes possible to examine the index file
in a hex util to determine what went wrong; the position gives a hint
about where to start looking.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
unpack-trees.c

index 2de6368b06db0b17ac285830a93e265b91816894..c5da0cb4c901c4c78635d116cc576f5b2517d066 100644 (file)
@@ -694,9 +694,11 @@ static int index_pos_by_traverse_info(struct name_entry *names,
        if (pos >= 0)
                BUG("This is a directory and should not exist in index");
        pos = -pos - 1;
-       if (!starts_with(o->src_index->cache[pos]->name, name.buf) ||
+       if (pos >= o->src_index->cache_nr ||
+           !starts_with(o->src_index->cache[pos]->name, name.buf) ||
            (pos > 0 && starts_with(o->src_index->cache[pos-1]->name, name.buf)))
-               BUG("pos must point at the first entry in this directory");
+               BUG("pos %d doesn't point to the first entry of %s in index",
+                   pos, name.buf);
        strbuf_release(&name);
        return pos;
 }