When parsing a tag, we may end up with a NULL "tagged" field when
there's a type mismatch (e.g., the tag claims to point to object X as a
commit, but we previously saw X as a blob in the same process), but we
do not otherwise indicate a parse failure to the caller.

This is similar to the case discussed in the previous commit, where a
commit could end up with a NULL tree field: while slightly convenient
for callers who want to overlook a corrupt object, it means that normal
callers have to explicitly deal with this case (rather than just relying
on the return code from parsing). And most don't, leading to segfault
fixes like the one in c77722b3ea (use get_tagged_oid(), 2019-09-05).

Let's address this more centrally, by returning an error code from the
parse itself, which most callers would already notice (adventurous
callers are free to ignore the error and continue looking at the

This also covers the case where the tag contains a nonsensical "type"
field (there we produced a user-visible error but still returned success
to the caller; now we'll produce a slightly better message and return an

Signed-off-by: Jeff King <p...@peff.net>
It's possible that c77722b3ea fixed all of the segfaults here, though of
course new callers must remember to use it instead of accessing
tag->tagged directly. We could _possibly_ get rid of that check now, but
that assumes that all of the caller notice parse_tag() or parse_object()
failing. Having both gives us belt-and-suspenders protection against a

 tag.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/tag.c b/tag.c
index bfa0e31435..6a51efda8d 100644
--- a/tag.c
+++ b/tag.c
@@ -167,10 +167,15 @@ int parse_tag_buffer(struct repository *r, struct tag 
*item, const void *data, u
        } else if (!strcmp(type, tag_type)) {
                item->tagged = (struct object *)lookup_tag(r, &oid);
        } else {
-               error("Unknown type %s", type);
-               item->tagged = NULL;
+               return error("unknown tag type '%s' in %s",
+                            type, oid_to_hex(&item->object.oid));
+       if (!item->tagged)
+               return error("bad tag pointer to %s in %s",
+                            oid_to_hex(&oid),
+                            oid_to_hex(&item->object.oid));
        if (bufptr + 4 < tail && starts_with(bufptr, "tag "))
                ;               /* good */

Reply via email to