Merge branch 'nd/repo-clear-keep-the-index'
authorJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 05:04:05 +0000 (14:04 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 05:04:05 +0000 (14:04 +0900)
the_repository->index is not a allocated piece of memory but
repo_clear() indiscriminately attempted to free(3) it, which has
been corrected.

* nd/repo-clear-keep-the-index:
repository: fix free problem with repo_clear(the_repository)

1  2 
repository.c
diff --combined repository.c
index beff3caa9e24a902e560372cdab3c337769c7c89,450852d9152ad791a2a63bc938e86061a55d34e2..02fe884603df56ea0996121152b7640afb56a48f
@@@ -1,78 -1,67 +1,78 @@@
  #include "cache.h"
  #include "repository.h"
 +#include "object-store.h"
  #include "config.h"
  #include "submodule-config.h"
  
  /* The main repository */
 -static struct repository the_repo = {
 -      NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, 0, 0
 -};
 -struct repository *the_repository = &the_repo;
 +static struct repository the_repo;
 +struct repository *the_repository;
  
 -static char *git_path_from_env(const char *envvar, const char *git_dir,
 -                             const char *path, int fromenv)
 +void initialize_the_repository(void)
  {
 -      if (fromenv) {
 -              const char *value = getenv(envvar);
 -              if (value)
 -                      return xstrdup(value);
 -      }
 +      the_repository = &the_repo;
  
 -      return xstrfmt("%s/%s", git_dir, path);
 +      the_repo.index = &the_index;
 +      the_repo.objects = raw_object_store_new();
 +      repo_set_hash_algo(&the_repo, GIT_HASH_SHA1);
  }
  
 -static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)
 +static void expand_base_dir(char **out, const char *in,
 +                          const char *base_dir, const char *def_in)
  {
 -      if (fromenv) {
 -              const char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);
 -              if (value) {
 -                      strbuf_addstr(sb, value);
 -                      return 1;
 -              }
 -      }
 -
 -      return get_common_dir_noenv(sb, gitdir);
 +      free(*out);
 +      if (in)
 +              *out = xstrdup(in);
 +      else
 +              *out = xstrfmt("%s/%s", base_dir, def_in);
  }
  
 -static void repo_setup_env(struct repository *repo)
 +static void repo_set_commondir(struct repository *repo,
 +                             const char *commondir)
  {
        struct strbuf sb = STRBUF_INIT;
  
 -      repo->different_commondir = find_common_dir(&sb, repo->gitdir,
 -                                                  !repo->ignore_env);
        free(repo->commondir);
 +
 +      if (commondir) {
 +              repo->different_commondir = 1;
 +              repo->commondir = xstrdup(commondir);
 +              return;
 +      }
 +
 +      repo->different_commondir = get_common_dir_noenv(&sb, repo->gitdir);
        repo->commondir = strbuf_detach(&sb, NULL);
 -      free(repo->objectdir);
 -      repo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,
 -                                          "objects", !repo->ignore_env);
 -      free(repo->graft_file);
 -      repo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,
 -                                           "info/grafts", !repo->ignore_env);
 -      free(repo->index_file);
 -      repo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,
 -                                           "index", !repo->ignore_env);
  }
  
 -void repo_set_gitdir(struct repository *repo, const char *path)
 +void repo_set_gitdir(struct repository *repo,
 +                   const char *root,
 +                   const struct set_gitdir_args *o)
  {
 -      const char *gitfile = read_gitfile(path);
 +      const char *gitfile = read_gitfile(root);
 +      /*
 +       * repo->gitdir is saved because the caller could pass "root"
 +       * that also points to repo->gitdir. We want to keep it alive
 +       * until after xstrdup(root). Then we can free it.
 +       */
        char *old_gitdir = repo->gitdir;
  
 -      repo->gitdir = xstrdup(gitfile ? gitfile : path);
 -      repo_setup_env(repo);
 -
 +      repo->gitdir = xstrdup(gitfile ? gitfile : root);
        free(old_gitdir);
 +
 +      repo_set_commondir(repo, o->commondir);
 +      expand_base_dir(&repo->objects->objectdir, o->object_dir,
 +                      repo->commondir, "objects");
 +      free(repo->objects->alternate_db);
 +      repo->objects->alternate_db = xstrdup_or_null(o->alternate_db);
 +      expand_base_dir(&repo->graft_file, o->graft_file,
 +                      repo->commondir, "info/grafts");
 +      expand_base_dir(&repo->index_file, o->index_file,
 +                      repo->gitdir, "index");
 +}
 +
 +void repo_set_hash_algo(struct repository *repo, int hash_algo)
 +{
 +      repo->hash_algo = &hash_algos[hash_algo];
  }
  
  /*
@@@ -85,7 -74,6 +85,7 @@@ static int repo_init_gitdir(struct repo
        int error = 0;
        char *abspath = NULL;
        const char *resolved_gitdir;
 +      struct set_gitdir_args args = { NULL };
  
        abspath = real_pathdup(gitdir, 0);
        if (!abspath) {
                goto out;
        }
  
 -      repo_set_gitdir(repo, resolved_gitdir);
 +      repo_set_gitdir(repo, resolved_gitdir, &args);
  
  out:
        free(abspath);
@@@ -135,14 -123,12 +135,14 @@@ static int read_and_verify_repository_f
   * Initialize 'repo' based on the provided 'gitdir'.
   * Return 0 upon success and a non-zero value upon failure.
   */
 -int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
 +int repo_init(struct repository *repo,
 +            const char *gitdir,
 +            const char *worktree)
  {
        struct repository_format format;
        memset(repo, 0, sizeof(*repo));
  
 -      repo->ignore_env = 1;
 +      repo->objects = raw_object_store_new();
  
        if (repo_init_gitdir(repo, gitdir))
                goto error;
        if (read_and_verify_repository_format(&format, repo->commondir))
                goto error;
  
 +      repo_set_hash_algo(repo, format.hash_algo);
 +
        if (worktree)
                repo_set_worktree(repo, worktree);
  
@@@ -176,7 -160,7 +176,7 @@@ int repo_submodule_init(struct reposito
        struct strbuf worktree = STRBUF_INIT;
        int ret = 0;
  
 -      sub = submodule_from_cache(superproject, &null_oid, path);
 +      sub = submodule_from_path(superproject, &null_oid, path);
        if (!sub) {
                ret = -1;
                goto out;
@@@ -218,14 -202,12 +218,14 @@@ void repo_clear(struct repository *repo
  {
        FREE_AND_NULL(repo->gitdir);
        FREE_AND_NULL(repo->commondir);
 -      FREE_AND_NULL(repo->objectdir);
        FREE_AND_NULL(repo->graft_file);
        FREE_AND_NULL(repo->index_file);
        FREE_AND_NULL(repo->worktree);
        FREE_AND_NULL(repo->submodule_prefix);
  
 +      raw_object_store_clear(repo->objects);
 +      FREE_AND_NULL(repo->objects);
 +
        if (repo->config) {
                git_configset_clear(repo->config);
                FREE_AND_NULL(repo->config);
  
        if (repo->index) {
                discard_index(repo->index);
-               FREE_AND_NULL(repo->index);
+               if (repo->index != &the_index)
+                       FREE_AND_NULL(repo->index);
        }
  }
  
@@@ -247,5 -230,5 +248,5 @@@ int repo_read_index(struct repository *
        if (!repo->index)
                repo->index = xcalloc(1, sizeof(*repo->index));
  
 -      return read_index_from(repo->index, repo->index_file);
 +      return read_index_from(repo->index, repo->index_file, repo->gitdir);
  }