Skip to content

Commit 59362e5

Browse files
committed
system_path(): always return free'able memory to the caller
The function sometimes returns a newly allocated string and sometimes returns a borrowed string, the latter of which the callers must not free(). The existing callers all assume that the return value belongs to the callee and most of them copy it with strdup() when they want to keep it around. They end up leaking the returned copy when the callee returned a new string because they cannot tell if they should free it. Change the contract between the callers and system_path() to make the returned string owned by the callers; they are responsible for freeing it when done, but they do not have to make their own copy to store it away. Adjust the callers to make sure they do not leak the returned string once they are done, but do not bother freeing it just before dying, exiting or exec'ing other program to avoid unnecessary churn. Reported-by: Alexander Kuleshov <kuleshovmail@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 7fa1365 commit 59362e5

4 files changed

Lines changed: 21 additions & 12 deletions

File tree

builtin/help.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,16 +322,18 @@ static void setup_man_path(void)
322322
{
323323
struct strbuf new_path = STRBUF_INIT;
324324
const char *old_path = getenv("MANPATH");
325+
char *git_man_path = system_path(GIT_MAN_PATH);
325326

326327
/* We should always put ':' after our path. If there is no
327328
* old_path, the ':' at the end will let 'man' to try
328329
* system-wide paths after ours to find the manual page. If
329330
* there is old_path, we need ':' as delimiter. */
330-
strbuf_addstr(&new_path, system_path(GIT_MAN_PATH));
331+
strbuf_addstr(&new_path, git_man_path);
331332
strbuf_addch(&new_path, ':');
332333
if (old_path)
333334
strbuf_addstr(&new_path, old_path);
334335

336+
free(git_man_path);
335337
setenv("MANPATH", new_path.buf, 1);
336338

337339
strbuf_release(&new_path);
@@ -381,8 +383,10 @@ static void show_info_page(const char *git_cmd)
381383
static void get_html_page_path(struct strbuf *page_path, const char *page)
382384
{
383385
struct stat st;
386+
char *to_free = NULL;
387+
384388
if (!html_path)
385-
html_path = system_path(GIT_HTML_PATH);
389+
html_path = to_free = system_path(GIT_HTML_PATH);
386390

387391
/* Check that we have a git documentation directory. */
388392
if (!strstr(html_path, "://")) {
@@ -393,6 +397,7 @@ static void get_html_page_path(struct strbuf *page_path, const char *page)
393397

394398
strbuf_init(page_path, 0);
395399
strbuf_addf(page_path, "%s/%s.html", html_path, page);
400+
free(to_free);
396401
}
397402

398403
/*

builtin/init-db.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,18 @@ static void copy_templates(const char *template_dir)
119119
DIR *dir;
120120
const char *git_dir = get_git_dir();
121121
int len = strlen(git_dir);
122+
char *to_free = NULL;
122123

123124
if (!template_dir)
124125
template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
125126
if (!template_dir)
126127
template_dir = init_db_template_dir;
127128
if (!template_dir)
128-
template_dir = system_path(DEFAULT_GIT_TEMPLATE_DIR);
129-
if (!template_dir[0])
129+
template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
130+
if (!template_dir[0]) {
131+
free(to_free);
130132
return;
133+
}
131134
template_len = strlen(template_dir);
132135
if (PATH_MAX <= (template_len+strlen("/config")))
133136
die(_("insanely long template path %s"), template_dir);
@@ -139,7 +142,7 @@ static void copy_templates(const char *template_dir)
139142
dir = opendir(template_path);
140143
if (!dir) {
141144
warning(_("templates not found %s"), template_dir);
142-
return;
145+
goto free_return;
143146
}
144147

145148
/* Make sure that template is from the correct vintage */
@@ -155,8 +158,7 @@ static void copy_templates(const char *template_dir)
155158
"a wrong format version %d from '%s'"),
156159
repository_format_version,
157160
template_dir);
158-
closedir(dir);
159-
return;
161+
goto close_free_return;
160162
}
161163

162164
memcpy(path, git_dir, len);
@@ -166,7 +168,10 @@ static void copy_templates(const char *template_dir)
166168
copy_templates_1(path, len,
167169
template_path, template_len,
168170
dir);
171+
close_free_return:
169172
closedir(dir);
173+
free_return:
174+
free(to_free);
170175
}
171176

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

exec_cmd.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
static const char *argv_exec_path;
77
static const char *argv0_path;
88

9-
const char *system_path(const char *path)
9+
char *system_path(const char *path)
1010
{
1111
#ifdef RUNTIME_PREFIX
1212
static const char *prefix;
@@ -16,7 +16,7 @@ const char *system_path(const char *path)
1616
struct strbuf d = STRBUF_INIT;
1717

1818
if (is_absolute_path(path))
19-
return path;
19+
return xstrdup(path);
2020

2121
#ifdef RUNTIME_PREFIX
2222
assert(argv0_path);
@@ -34,8 +34,7 @@ const char *system_path(const char *path)
3434
#endif
3535

3636
strbuf_addf(&d, "%s/%s", prefix, path);
37-
path = strbuf_detach(&d, NULL);
38-
return path;
37+
return strbuf_detach(&d, NULL);
3938
}
4039

4140
const char *git_extract_argv0_path(const char *argv0)

exec_cmd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ extern const char **prepare_git_cmd(const char **argv);
99
extern int execv_git_cmd(const char **argv); /* NULL terminated */
1010
LAST_ARG_MUST_BE_NULL
1111
extern int execl_git_cmd(const char *cmd, ...);
12-
extern const char *system_path(const char *path);
12+
extern char *system_path(const char *path);
1313

1414
#endif /* GIT_EXEC_CMD_H */

0 commit comments

Comments
 (0)