On 3/23/2022 2:03 PM, Josh Steadmon wrote: > prepare_repo_settings() initializes a `struct repository` with various > default config options and settings read from a repository-local config > file. In 44c7e62 (2021-12-06, repo-settings:prepare_repo_settings only > in git repos), prepare_repo_settings was changed to issue a BUG() if it > is called by a process whose CWD is not a Git repository. This approach > was suggested in [1]. > > This breaks fuzz-commit-graph, which attempts to parse arbitrary > fuzzing-engine-provided bytes as a commit graph file. > commit-graph.c:parse_commit_graph() calls prepare_repo_settings(), but > since we run the fuzz tests without a valid repository, we are hitting > the BUG() from 44c7e62 for every test case. > > Fix this by refactoring prepare_repo_settings() such that it sets > default options unconditionally; if its process is in a Git repository, > it will also load settings from the local config. This eliminates the > need for a BUG() when not in a repository. I think you have the right idea and this can work. > - /* Booleans config or default, cascades to other settings */ > - repo_cfg_bool(r, "feature.manyfiles", &manyfiles, 0); > - repo_cfg_bool(r, "feature.experimental", &experimental, 0); > + if (r->gitdir) { > + /* Booleans config or default, cascades to other settings */ > + repo_cfg_bool(r, "feature.manyfiles", &manyfiles, 0); > + repo_cfg_bool(r, "feature.experimental", &experimental, 0); However, this giant if block is going to be a bit unwieldy, especially as we add settings in the future. Ignoring whitespace, this is your diff: diff --git a/repo-settings.c b/repo-settings.c index b4fbd16cdc..d154b37007 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -17,9 +17,6 @@ void prepare_repo_settings(struct repository *r) char *strval; int manyfiles; - if (!r->gitdir) - BUG("Cannot add settings for uninitialized repository"); - if (r->settings.initialized++) return; @@ -28,6 +25,7 @@ void prepare_repo_settings(struct repository *r) r->settings.core_untracked_cache = UNTRACKED_CACHE_KEEP; r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_CONSECUTIVE; + if (r->gitdir) { /* Booleans config or default, cascades to other settings */ repo_cfg_bool(r, "feature.manyfiles", &manyfiles, 0); repo_cfg_bool(r, "feature.experimental", &experimental, 0); @@ -50,16 +48,6 @@ void prepare_repo_settings(struct repository *r) repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1); repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0); (Adding the if) - /* - * The GIT_TEST_MULTI_PACK_INDEX variable is special in that - * either it *or* the config sets - * r->settings.core_multi_pack_index if true. We don't take - * the environment variable if it exists (even if false) over - * any config, as in most other cases. - */ - if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) - r->settings.core_multi_pack_index = 1; - /* * Non-boolean config */ @@ -93,6 +81,17 @@ void prepare_repo_settings(struct repository *r) else die("unknown fetch negotiation algorithm '%s'", strval); } + } + + /* + * The GIT_TEST_MULTI_PACK_INDEX variable is special in that + * either it *or* the config sets + * r->settings.core_multi_pack_index if true. We don't take + * the environment variable if it exists (even if false) over + * any config, as in most other cases. + */ + if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) + r->settings.core_multi_pack_index = 1; (Moving this to group with other no-dir settings.) I think what you're really trying to do is if (r->gitdir) (Load settings that require a repo) (Load settings that work without a repo.) I think that you'd be better off extracting the two types of config into helper methods (prepare_gitdir_settings()/prepare_nodir_settings()?) across two patches, then in a third removing the BUG and inserting the if (r->gitdir) above. Does that seem reasonable? Thanks, -Stolee