Skip to content

Commit fe7b273

Browse files
chriscoolgitster
authored andcommitted
promisor-remote: fix segfault when remote URL is missing
Using strvec_push() to push `NULL` into a 'strvec' results in a segfault, because `xstrdup(NULL)` crashes. So when an URL is missing from the config, let's push an empty string instead of `NULL` into the 'strvec' that stores URLs. We could have modified strvec_push() to behave like strvec_push_nodup() and accept `NULL`, but it's not clear that it's the right thing to do for the strvec API. 'strvec' is a kind of NULL terminated array that is designed to be compatible with 'argv' variables used on the command line. So we might want to disallow pushing any `NULL` in it instead. It's also not clear if `xstrdup(NULL)` should crash or BUG or just return NULL. For all these reasons, let's just focus on fixing the issue in "promisor-remote.c" and let's leave improving the strvec API and/or xstrdup() for a future effort. While at it let's warn and reject the remote, in the 'KnownUrl' case, when no URL is advertised by the server or no URL is configured on the client for a remote name advertised by the server and configured on the client. This is on par with a warning already emitted when URLs are different in the same case. Signed-off-by: Christian Couder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5040f9f commit fe7b273

File tree

2 files changed

+56
-3
lines changed

2 files changed

+56
-3
lines changed

promisor-remote.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,15 @@ static void promisor_info_vecs(struct repository *repo,
323323
promisor_remote_init(repo);
324324

325325
for (r = repo->promisor_remote_config->promisors; r; r = r->next) {
326-
char *url;
326+
char *url = NULL;
327+
const char *url_pushed = "";
327328
char *url_key = xstrfmt("remote.%s.url", r->name);
328329

330+
if (!git_config_get_string(url_key, &url) && url)
331+
url_pushed = url;
332+
329333
strvec_push(names, r->name);
330-
strvec_push(urls, git_config_get_string(url_key, &url) ? NULL : url);
334+
strvec_push(urls, url_pushed);
331335

332336
free(url);
333337
free(url_key);
@@ -356,7 +360,7 @@ char *promisor_remote_info(struct repository *repo)
356360
strbuf_addch(&sb, ';');
357361
strbuf_addstr(&sb, "name=");
358362
strbuf_addstr_urlencode(&sb, names.v[i], allow_unsanitized);
359-
if (urls.v[i]) {
363+
if (*urls.v[i]) {
360364
strbuf_addstr(&sb, ",url=");
361365
strbuf_addstr_urlencode(&sb, urls.v[i], allow_unsanitized);
362366
}
@@ -409,6 +413,16 @@ static int should_accept_remote(enum accept_promisor accept,
409413
if (accept != ACCEPT_KNOWN_URL)
410414
BUG("Unhandled 'enum accept_promisor' value '%d'", accept);
411415

416+
if (!remote_url) {
417+
warning(_("no URL advertised for remote '%s'"), remote_name);
418+
return 0;
419+
}
420+
421+
if (!*urls->v[i]) {
422+
warning(_("no URL configured for remote '%s'"), remote_name);
423+
return 0;
424+
}
425+
412426
if (!strcmp(urls->v[i], remote_url))
413427
return 1;
414428

t/t5710-promisor-remote-capability.sh

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,25 @@ test_expect_success "clone with 'KnownName' and different remote names" '
193193
initialize_server 1 "$oid"
194194
'
195195

196+
test_expect_success "clone with 'KnownName' and missing URL in the config" '
197+
git -C server config promisor.advertise true &&
198+
199+
# Clone from server to create a client
200+
# Lazy fetching by the client from the LOP will fail because of the
201+
# missing URL in the client config, so the server will have to lazy
202+
# fetch from the LOP.
203+
GIT_NO_LAZY_FETCH=0 git clone -c remote.lop.promisor=true \
204+
-c promisor.acceptfromserver=KnownName \
205+
--no-local --filter="blob:limit=5k" server client &&
206+
test_when_finished "rm -rf client" &&
207+
208+
# Check that the largest object is not missing on the server
209+
check_missing_objects server 0 "" &&
210+
211+
# Reinitialize server so that the largest object is missing again
212+
initialize_server 1 "$oid"
213+
'
214+
196215
test_expect_success "clone with promisor.acceptfromserver set to 'KnownUrl'" '
197216
git -C server config promisor.advertise true &&
198217
@@ -228,6 +247,26 @@ test_expect_success "clone with 'KnownUrl' and different remote urls" '
228247
initialize_server 1 "$oid"
229248
'
230249

250+
test_expect_success "clone with 'KnownUrl' and url not advertised" '
251+
git -C server config promisor.advertise true &&
252+
253+
git -C server config unset remote.lop.url &&
254+
test_when_finished "git -C server config set remote.lop.url \"file://$(pwd)/lop\"" &&
255+
256+
# Clone from server to create a client
257+
# It should fail because the client will reject the LOP
258+
# as URLs are different, and the server cannot lazy fetch as
259+
# the LOP URL is missing.
260+
GIT_NO_LAZY_FETCH=0 test_must_fail git clone -c remote.lop.promisor=true \
261+
-c remote.lop.fetch="+refs/heads/*:refs/remotes/lop/*" \
262+
-c remote.lop.url="file://$(pwd)/lop" \
263+
-c promisor.acceptfromserver=KnownUrl \
264+
--no-local --filter="blob:limit=5k" server client &&
265+
266+
# Check that the largest object is still missing on the server
267+
check_missing_objects server 1 "$oid"
268+
'
269+
231270
test_expect_success "clone with promisor.advertise set to 'true' but don't delete the client" '
232271
git -C server config promisor.advertise true &&
233272

0 commit comments

Comments
 (0)