Skip to content

Commit 52595c1

Browse files
peffgitster
authored andcommitted
remote: transfer ownership of memory in add_url(), etc
Many of the internal functions in remote.c take const strings and store them forever in instances of "struct remote". Since the functions are internal and callers are aware of the convention, this seems to mostly work and not cause leaks. But there are some issues: - it's impossible to clear any of the arrays, because the data dependencies between them are too muddled (if you free() a string, it might also be referenced from another array, causing a user-after-free; but if you don't, that might be the last reference, causing a leak). This is mostly of interest for further refactoring and features, but there's at least one spot that's already a problem. In alias_all_urls(), we replace elements of remote->url and remote->pushurl with their aliased forms, dropping references to the original. - sometimes strings from outside callers make their way in. For example, calling remote_get("foo") when there is no configured "foo" remote will create a remote struct with the single url "foo". But we'll do so by holding on to the string passed to remote_get() forever. In practice I think this works out because we'd usually pass in a string that lasts the length of the program (a string literal, or argv reference, or other data structure allocated in the main function). But it's a rather subtle requirement. Instead, let's have remote->url and remote->pushurl own their string memory. They'll copy the const strings that are passed in, and callers can stop making their own copies. Likewise, when we overwrite an entry, we can free the memory it points to, fixing the leak mentioned above. We'll leave the struct members as "const" since they are visible to the outside world, and shouldn't usually be touched. This requires casting on free() for now, but we'll clean that further in a future patch. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent aa0595f commit 52595c1

File tree

1 file changed

+19
-14
lines changed

1 file changed

+19
-14
lines changed

remote.c

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ static char *alias_url(const char *url, struct rewrites *r)
6464
static void add_url(struct remote *remote, const char *url)
6565
{
6666
ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
67-
remote->url[remote->url_nr++] = url;
67+
remote->url[remote->url_nr++] = xstrdup(url);
6868
}
6969

7070
static void add_pushurl(struct remote *remote, const char *pushurl)
7171
{
7272
ALLOC_GROW(remote->pushurl, remote->pushurl_nr + 1, remote->pushurl_alloc);
73-
remote->pushurl[remote->pushurl_nr++] = pushurl;
73+
remote->pushurl[remote->pushurl_nr++] = xstrdup(pushurl);
7474
}
7575

7676
static void add_pushurl_alias(struct remote_state *remote_state,
@@ -79,6 +79,7 @@ static void add_pushurl_alias(struct remote_state *remote_state,
7979
char *alias = alias_url(url, &remote_state->rewrites_push);
8080
if (alias)
8181
add_pushurl(remote, alias);
82+
free(alias);
8283
}
8384

8485
static void add_url_alias(struct remote_state *remote_state,
@@ -87,6 +88,7 @@ static void add_url_alias(struct remote_state *remote_state,
8788
char *alias = alias_url(url, &remote_state->rewrites);
8889
add_url(remote, alias ? alias : url);
8990
add_pushurl_alias(remote_state, remote, url);
91+
free(alias);
9092
}
9193

9294
struct remotes_hash_key {
@@ -293,7 +295,7 @@ static void read_remotes_file(struct remote_state *remote_state,
293295

294296
if (skip_prefix(buf.buf, "URL:", &v))
295297
add_url_alias(remote_state, remote,
296-
xstrdup(skip_spaces(v)));
298+
skip_spaces(v));
297299
else if (skip_prefix(buf.buf, "Push:", &v))
298300
refspec_append(&remote->push, skip_spaces(v));
299301
else if (skip_prefix(buf.buf, "Pull:", &v))
@@ -336,7 +338,7 @@ static void read_branches_file(struct remote_state *remote_state,
336338
else
337339
frag = to_free = repo_default_branch_name(the_repository, 0);
338340

339-
add_url_alias(remote_state, remote, strbuf_detach(&buf, NULL));
341+
add_url_alias(remote_state, remote, buf.buf);
340342
refspec_appendf(&remote->fetch, "refs/heads/%s:refs/heads/%s",
341343
frag, remote->name);
342344

@@ -347,6 +349,7 @@ static void read_branches_file(struct remote_state *remote_state,
347349
refspec_appendf(&remote->push, "HEAD:refs/heads/%s", frag);
348350
remote->fetch_tags = 1; /* always auto-follow */
349351

352+
strbuf_release(&buf);
350353
free(to_free);
351354
}
352355

@@ -431,15 +434,13 @@ static int handle_config(const char *key, const char *value,
431434
else if (!strcmp(subkey, "prunetags"))
432435
remote->prune_tags = git_config_bool(key, value);
433436
else if (!strcmp(subkey, "url")) {
434-
char *v;
435-
if (git_config_string(&v, key, value))
436-
return -1;
437-
add_url(remote, v);
437+
if (!value)
438+
return config_error_nonbool(key);
439+
add_url(remote, value);
438440
} else if (!strcmp(subkey, "pushurl")) {
439-
char *v;
440-
if (git_config_string(&v, key, value))
441-
return -1;
442-
add_pushurl(remote, v);
441+
if (!value)
442+
return config_error_nonbool(key);
443+
add_pushurl(remote, value);
443444
} else if (!strcmp(subkey, "push")) {
444445
char *v;
445446
if (git_config_string(&v, key, value))
@@ -495,8 +496,10 @@ static void alias_all_urls(struct remote_state *remote_state)
495496
for (j = 0; j < remote_state->remotes[i]->pushurl_nr; j++) {
496497
char *alias = alias_url(remote_state->remotes[i]->pushurl[j],
497498
&remote_state->rewrites);
498-
if (alias)
499+
if (alias) {
500+
free((char *)remote_state->remotes[i]->pushurl[j]);
499501
remote_state->remotes[i]->pushurl[j] = alias;
502+
}
500503
}
501504
add_pushurl_aliases = remote_state->remotes[i]->pushurl_nr == 0;
502505
for (j = 0; j < remote_state->remotes[i]->url_nr; j++) {
@@ -507,8 +510,10 @@ static void alias_all_urls(struct remote_state *remote_state)
507510
remote_state->remotes[i]->url[j]);
508511
alias = alias_url(remote_state->remotes[i]->url[j],
509512
&remote_state->rewrites);
510-
if (alias)
513+
if (alias) {
514+
free((char *)remote_state->remotes[i]->url[j]);
511515
remote_state->remotes[i]->url[j] = alias;
516+
}
512517
}
513518
}
514519
}

0 commit comments

Comments
 (0)