Skip to content

Commit

Permalink
scalar: avoid segfault in reconfigure --all
Browse files Browse the repository at this point in the history
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.

This NULL reference appears to be due to the way the loop is abusing the
the_repository pointer, pointing it to a local repository struct after
discovering that the current directory is a valid Git repository. This
repo-swapping bit was in the original implementation from 4582676
(scalar: teach 'reconfigure' to optionally handle all registered
enlistments, 2021-12-03), but only recently started segfaulting while
trying to parse the HEAD reference. This also only happens on the
_second_ repository in the list, so does not reproduce if there is only
one registered repo.

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>
  • Loading branch information
derrickstolee and pks-t committed May 4, 2024
1 parent e326e52 commit 5be703b
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 3 deletions.
10 changes: 7 additions & 3 deletions scalar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
38 changes: 38 additions & 0 deletions t/t9210-scalar.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand Down

0 comments on commit 5be703b

Please sign in to comment.