]> git.ipfire.org Git - thirdparty/git.git/commitdiff
revision: retain argv NULL invariant in setup_revisions()
authorJeff King <peff@peff.net>
Fri, 19 Sep 2025 22:51:46 +0000 (18:51 -0400)
committerJunio C Hamano <gitster@pobox.com>
Mon, 22 Sep 2025 21:27:03 +0000 (14:27 -0700)
In an argc/argv pair, the entry for argv[argc] is generally NULL. You
can iterate by counting up to argc, or by looking for the NULL entry in
argv.

When we pass such a pair to setup_revisions(), it shrinks argc to
account for the options we consumed and returns the result to the
caller. But it doesn't touch the entries after the reduced argc. So
argv[argc] will be left pointing at some arbitrary entry rather than
NULL.

This isn't the source of any known bugs, since all callers are aware of
the limitation and act accordingly. But it's a possible gotcha that may
be easy to miss.

Let's set the new argv[argc] to NULL, taking care to free it if the
caller asked us to do so.

It is tempting to do likewise for all of the entries afterwards, too, as
some of them may also need to be freed (e.g., if coming from a strvec).
But doing so isn't entirely trivial, as we munge argc in the function
(e.g., when we find "--" and move all of the entries after it into the
prune_data list). It would be possible with some light refactoring, but
it's probably not worth it. Nobody should ever look at them (they are
beyond the revised argc and past the NULL argv entry) outside of strvec
cleanup, and setup_revisions_from_strvec() already handles this case.

There's one other interesting gotcha: many callers which do not want to
provide arguments just pass 0/NULL for argc/argv. We need to check for
this case before assigning the final NULL.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
revision.c

index d4788aedab8d6eed06ca2d87363148fa69420b5a..ba14ac3da12572af2415c74e7733577067f0402a 100644 (file)
@@ -3175,6 +3175,12 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                revs->show_notes_given = 1;
        }
 
+       if (argv) {
+               if (opt && opt->free_removed_argv_elements)
+                       free((char *)argv[left]);
+               argv[left] = NULL;
+       }
+
        return left;
 }