]> git.ipfire.org Git - thirdparty/git.git/commitdiff
scalar: avoid segfault in reconfigure --all
authorDerrick Stolee <stolee@gmail.com>
Wed, 8 May 2024 00:05:49 +0000 (00:05 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 8 May 2024 00:51:12 +0000 (17:51 -0700)
During the latest v2.45.0 update, 'scalar reconfigure --all' started to
segfault on my machine. Breaking it down via the debugger, it was
faulting on a NULL reference to the_hash_algo, which is a macro pointing
to the_repository->hash_algo.

In my case, this is due to one of my repositories having a detached HEAD,
which requires get_oid_hex() to parse that the HEAD reference is valid.
Another way to cause a failure is to use the "includeIf.onbranch" config
key, which will lead to a BUG() statement.

My first inclination was to try to refactor cmd_reconfigure() to execute
'git for-each-repo' instead of this loop. In addition to the difficulty
of executing 'scalar reconfigure' within 'git for-each-repo', it would
be difficult to perform the clean-up logic for non-existent repos if we
relied on that child process.

Instead, I chose to move the temporary repo to be within the loop and
reinstate the_repository to its old value after we are done performing
logic on the current array item.

Add tests to t9210-scalar.sh to test 'scalar reconfigure --all' with
multiple registered repos. There are two different ways that the old
use of the_repository could trigger bugs. These issues are being solved
independently to be more careful about the_repository being
uninitialized, but the change in this patch around the use of
the_repository is still a good safety precaution.

Co-authored-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
scalar.c
t/t9210-scalar.sh

index fb2940c2a00c94d806319dc8d45e8ffed1231c17..7234049a1b87c046d26db57082e368b9ba68812f 100644 (file)
--- a/scalar.c
+++ b/scalar.c
@@ -645,7 +645,6 @@ static int cmd_reconfigure(int argc, const char **argv)
        };
        struct string_list scalar_repos = STRING_LIST_INIT_DUP;
        int i, res = 0;
-       struct repository r = { NULL };
        struct strbuf commondir = STRBUF_INIT, gitdir = STRBUF_INIT;
 
        argc = parse_options(argc, argv, NULL, options,
@@ -665,6 +664,7 @@ static int cmd_reconfigure(int argc, const char **argv)
 
        for (i = 0; i < scalar_repos.nr; i++) {
                int succeeded = 0;
+               struct repository *old_repo, r = { NULL };
                const char *dir = scalar_repos.items[i].string;
 
                strbuf_reset(&commondir);
@@ -712,13 +712,17 @@ static int cmd_reconfigure(int argc, const char **argv)
 
                git_config_clear();
 
+               if (repo_init(&r, gitdir.buf, commondir.buf))
+                       goto loop_end;
+
+               old_repo = the_repository;
                the_repository = &r;
-               r.commondir = commondir.buf;
-               r.gitdir = gitdir.buf;
 
                if (set_recommended_config(1) >= 0)
                        succeeded = 1;
 
+               the_repository = old_repo;
+
 loop_end:
                if (!succeeded) {
                        res = -1;
index 428339e342751e02e3c9fe5b8053c0ccc6fee4b8..a41b4fcc0859db4d40137ce768a528c237975456 100755 (executable)
@@ -180,6 +180,44 @@ test_expect_success 'scalar reconfigure' '
        test true = "$(git -C one/src config core.preloadIndex)"
 '
 
+test_expect_success 'scalar reconfigure --all with includeIf.onbranch' '
+       repos="two three four" &&
+       for num in $repos
+       do
+               git init $num/src &&
+               scalar register $num/src &&
+               git -C $num/src config includeif."onbranch:foo".path something &&
+               git -C $num/src config core.preloadIndex false || return 1
+       done &&
+
+       scalar reconfigure --all &&
+
+       for num in $repos
+       do
+               test true = "$(git -C $num/src config core.preloadIndex)" || return 1
+       done
+'
+
+ test_expect_success 'scalar reconfigure --all with detached HEADs' '
+       repos="two three four" &&
+       for num in $repos
+       do
+               rm -rf $num/src &&
+               git init $num/src &&
+               scalar register $num/src &&
+               git -C $num/src config core.preloadIndex false &&
+               test_commit -C $num/src initial &&
+               git -C $num/src switch --detach HEAD || return 1
+       done &&
+
+       scalar reconfigure --all &&
+
+       for num in $repos
+       do
+               test true = "$(git -C $num/src config core.preloadIndex)" || return 1
+       done
+'
+
 test_expect_success '`reconfigure -a` removes stale config entries' '
        git init stale/src &&
        scalar register stale &&