prefix_ref_iterator: don't trim too much
authorMichael Haggerty <mhagger@alum.mit.edu>
Mon, 22 May 2017 14:17:35 +0000 (16:17 +0200)
committerJunio C Hamano <gitster@pobox.com>
Tue, 23 May 2017 05:29:52 +0000 (14:29 +0900)
The `trim` parameter can be set independently of `prefix`. So if some
caller were to set `trim` to be greater than `strlen(prefix)`, we
could end up pointing the `refname` field of the iterator past the NUL
of the actual reference name string.

That can't happen currently, because `trim` is always set either to
zero or to `strlen(prefix)`. But even the latter could lead to
confusion, if a refname is exactly equal to the prefix, because then
we would set the outgoing `refname` to the empty string.

And we're about to decouple the `prefix` and `trim` arguments even
more, so let's be cautious here. Report a bug if ever asked to trim a
reference whose name is not longer than `trim`.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs/iterator.c
index bce1f192f7d4c7e2e3efc6d5ea7df4560cb3cc0a..4cf449ef660e2bc9ee5b6ddb4efd8662d27e12b3 100644 (file)
@@ -292,7 +292,23 @@ static int prefix_ref_iterator_advance(struct ref_iterator *ref_iterator)
                if (!starts_with(iter->iter0->refname, iter->prefix))
                        continue;
 
-               iter->base.refname = iter->iter0->refname + iter->trim;
+               if (iter->trim) {
+                       /*
+                        * It is nonsense to trim off characters that
+                        * you haven't already checked for via a
+                        * prefix check, whether via this
+                        * `prefix_ref_iterator` or upstream in
+                        * `iter0`). So if there wouldn't be at least
+                        * one character left in the refname after
+                        * trimming, report it as a bug:
+                        */
+                       if (strlen(iter->iter0->refname) <= iter->trim)
+                               die("BUG: attempt to trim too many characters");
+                       iter->base.refname = iter->iter0->refname + iter->trim;
+               } else {
+                       iter->base.refname = iter->iter0->refname;
+               }
+
                iter->base.oid = iter->iter0->oid;
                iter->base.flags = iter->iter0->flags;
                return ITER_OK;