Skip to content

Commit 6b5688b

Browse files
committed
Merge branch 'ma/clear-repository-format'
The setup code has been cleaned up to avoid leaks around the repository_format structure. * ma/clear-repository-format: setup: fix memory leaks with `struct repository_format` setup: free old value before setting `work_tree`
2 parents 83b13e2 + e8805af commit 6b5688b

File tree

5 files changed

+63
-18
lines changed

5 files changed

+63
-18
lines changed

builtin/init-db.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ static void copy_templates(const char *template_dir)
9696
struct strbuf path = STRBUF_INIT;
9797
struct strbuf template_path = STRBUF_INIT;
9898
size_t template_len;
99-
struct repository_format template_format;
99+
struct repository_format template_format = REPOSITORY_FORMAT_INIT;
100100
struct strbuf err = STRBUF_INIT;
101101
DIR *dir;
102102
char *to_free = NULL;
@@ -148,6 +148,7 @@ static void copy_templates(const char *template_dir)
148148
free(to_free);
149149
strbuf_release(&path);
150150
strbuf_release(&template_path);
151+
clear_repository_format(&template_format);
151152
}
152153

153154
static int git_init_db_config(const char *k, const char *v, void *cb)

cache.h

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,10 @@ extern char *repository_format_partial_clone;
962962
extern const char *core_partial_clone_filter_default;
963963
extern int repository_format_worktree_config;
964964

965+
/*
966+
* You _have_ to initialize a `struct repository_format` using
967+
* `= REPOSITORY_FORMAT_INIT` before calling `read_repository_format()`.
968+
*/
965969
struct repository_format {
966970
int version;
967971
int precious_objects;
@@ -973,14 +977,35 @@ struct repository_format {
973977
struct string_list unknown_extensions;
974978
};
975979

980+
/*
981+
* Always use this to initialize a `struct repository_format`
982+
* to a well-defined, default state before calling
983+
* `read_repository()`.
984+
*/
985+
#define REPOSITORY_FORMAT_INIT \
986+
{ \
987+
.version = -1, \
988+
.is_bare = -1, \
989+
.hash_algo = GIT_HASH_SHA1, \
990+
.unknown_extensions = STRING_LIST_INIT_DUP, \
991+
}
992+
976993
/*
977994
* Read the repository format characteristics from the config file "path" into
978-
* "format" struct. Returns the numeric version. On error, -1 is returned,
979-
* format->version is set to -1, and all other fields in the struct are
980-
* undefined.
995+
* "format" struct. Returns the numeric version. On error, or if no version is
996+
* found in the configuration, -1 is returned, format->version is set to -1,
997+
* and all other fields in the struct are set to the default configuration
998+
* (REPOSITORY_FORMAT_INIT). Always initialize the struct using
999+
* REPOSITORY_FORMAT_INIT before calling this function.
9811000
*/
9821001
int read_repository_format(struct repository_format *format, const char *path);
9831002

1003+
/*
1004+
* Free the memory held onto by `format`, but not the struct itself.
1005+
* (No need to use this after `read_repository_format()` fails.)
1006+
*/
1007+
void clear_repository_format(struct repository_format *format);
1008+
9841009
/*
9851010
* Verify that the repository described by repository_format is something we
9861011
* can read. If it is, return 0. Otherwise, return -1, and "err" will describe

repository.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ int repo_init(struct repository *repo,
157157
const char *gitdir,
158158
const char *worktree)
159159
{
160-
struct repository_format format;
160+
struct repository_format format = REPOSITORY_FORMAT_INIT;
161161
memset(repo, 0, sizeof(*repo));
162162

163163
repo->objects = raw_object_store_new();
@@ -174,6 +174,7 @@ int repo_init(struct repository *repo,
174174
if (worktree)
175175
repo_set_worktree(repo, worktree);
176176

177+
clear_repository_format(&format);
177178
return 0;
178179

179180
error:

setup.c

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ static int read_worktree_config(const char *var, const char *value, void *vdata)
411411
} else if (strcmp(var, "core.worktree") == 0) {
412412
if (!value)
413413
return config_error_nonbool(var);
414+
free(data->work_tree);
414415
data->work_tree = xstrdup(value);
415416
}
416417
return 0;
@@ -476,7 +477,7 @@ static int check_repository_format_gently(const char *gitdir, struct repository_
476477
}
477478

478479
repository_format_precious_objects = candidate->precious_objects;
479-
repository_format_partial_clone = candidate->partial_clone;
480+
repository_format_partial_clone = xstrdup_or_null(candidate->partial_clone);
480481
repository_format_worktree_config = candidate->worktree_config;
481482
string_list_clear(&candidate->unknown_extensions, 0);
482483

@@ -499,27 +500,38 @@ static int check_repository_format_gently(const char *gitdir, struct repository_
499500
}
500501
if (candidate->work_tree) {
501502
free(git_work_tree_cfg);
502-
git_work_tree_cfg = candidate->work_tree;
503+
git_work_tree_cfg = xstrdup(candidate->work_tree);
503504
inside_work_tree = -1;
504505
}
505-
} else {
506-
free(candidate->work_tree);
507506
}
508507

509508
return 0;
510509
}
511510

511+
static void init_repository_format(struct repository_format *format)
512+
{
513+
const struct repository_format fresh = REPOSITORY_FORMAT_INIT;
514+
515+
memcpy(format, &fresh, sizeof(fresh));
516+
}
517+
512518
int read_repository_format(struct repository_format *format, const char *path)
513519
{
514-
memset(format, 0, sizeof(*format));
515-
format->version = -1;
516-
format->is_bare = -1;
517-
format->hash_algo = GIT_HASH_SHA1;
518-
string_list_init(&format->unknown_extensions, 1);
520+
clear_repository_format(format);
519521
git_config_from_file(check_repo_format, path, format);
522+
if (format->version == -1)
523+
clear_repository_format(format);
520524
return format->version;
521525
}
522526

527+
void clear_repository_format(struct repository_format *format)
528+
{
529+
string_list_clear(&format->unknown_extensions, 0);
530+
free(format->work_tree);
531+
free(format->partial_clone);
532+
init_repository_format(format);
533+
}
534+
523535
int verify_repository_format(const struct repository_format *format,
524536
struct strbuf *err)
525537
{
@@ -997,7 +1009,7 @@ int discover_git_directory(struct strbuf *commondir,
9971009
struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
9981010
size_t gitdir_offset = gitdir->len, cwd_len;
9991011
size_t commondir_offset = commondir->len;
1000-
struct repository_format candidate;
1012+
struct repository_format candidate = REPOSITORY_FORMAT_INIT;
10011013

10021014
if (strbuf_getcwd(&dir))
10031015
return -1;
@@ -1034,9 +1046,11 @@ int discover_git_directory(struct strbuf *commondir,
10341046
strbuf_release(&err);
10351047
strbuf_setlen(commondir, commondir_offset);
10361048
strbuf_setlen(gitdir, gitdir_offset);
1049+
clear_repository_format(&candidate);
10371050
return -1;
10381051
}
10391052

1053+
clear_repository_format(&candidate);
10401054
return 0;
10411055
}
10421056

@@ -1045,7 +1059,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
10451059
static struct strbuf cwd = STRBUF_INIT;
10461060
struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT;
10471061
const char *prefix = NULL;
1048-
struct repository_format repo_fmt;
1062+
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
10491063

10501064
/*
10511065
* We may have read an incomplete configuration before
@@ -1157,6 +1171,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
11571171

11581172
strbuf_release(&dir);
11591173
strbuf_release(&gitdir);
1174+
clear_repository_format(&repo_fmt);
11601175

11611176
return prefix;
11621177
}
@@ -1214,9 +1229,10 @@ int git_config_perm(const char *var, const char *value)
12141229

12151230
void check_repository_format(void)
12161231
{
1217-
struct repository_format repo_fmt;
1232+
struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
12181233
check_repository_format_gently(get_git_dir(), &repo_fmt, NULL);
12191234
startup_info->have_repository = 1;
1235+
clear_repository_format(&repo_fmt);
12201236
}
12211237

12221238
/*

worktree.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ int submodule_uses_worktrees(const char *path)
444444
DIR *dir;
445445
struct dirent *d;
446446
int ret = 0;
447-
struct repository_format format;
447+
struct repository_format format = REPOSITORY_FORMAT_INIT;
448448

449449
submodule_gitdir = git_pathdup_submodule(path, "%s", "");
450450
if (!submodule_gitdir)
@@ -462,8 +462,10 @@ int submodule_uses_worktrees(const char *path)
462462
read_repository_format(&format, sb.buf);
463463
if (format.version != 0) {
464464
strbuf_release(&sb);
465+
clear_repository_format(&format);
465466
return 1;
466467
}
468+
clear_repository_format(&format);
467469

468470
/* Replace config by worktrees. */
469471
strbuf_setlen(&sb, sb.len - strlen("config"));

0 commit comments

Comments
 (0)