fetch: create status table using strbuf

When we fetch from a remote, we print a status table like: From url * [new branch] foo -> origin/foo We create this table in a static buffer using sprintf. If the remote refnames are long, they can overflow this buffer and smash the stack. Instead, let's use a strbuf to build the string. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Dec 8, 2011 at 03:43 UTC 5914f2d057c259668695bccab8e9bec3a4bead53
1 file changed +49 -38
builtin/fetch.c
+49 -38
@@ -239,23 +239,23 @@ static int s_update_ref(const char *action,
239
240 static int update_local_ref(struct ref *ref,
241 const char *remote,
242 - char *display)
242 + struct strbuf *display)
243 {
244 struct commit *current = NULL, *updated;
245 enum object_type type;
246 struct branch *current_branch = branch_get(NULL);
247 const char *pretty_ref = prettify_refname(ref->name);
248
249 - *display = 0;
249 type = sha1_object_info(ref->new_sha1, NULL);
250 if (type < 0)
251 die(_("object %s not found"), sha1_to_hex(ref->new_sha1));
252
253 if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
254 if (verbosity > 0)
256 - sprintf(display, "= %-*s %-*s -> %s", TRANSPORT_SUMMARY_WIDTH,
257 - _("[up to date]"), REFCOL_WIDTH, remote,
258 - pretty_ref);
255 + strbuf_addf(display, "= %-*s %-*s -> %s",
256 + TRANSPORT_SUMMARY_WIDTH,
257 + _("[up to date]"), REFCOL_WIDTH,
258 + remote, pretty_ref);
259 return 0;
260 }
261
@@ -267,9 +267,10 @@ static int update_local_ref(struct ref *ref,
267 * If this is the head, and it's not okay to update
268 * the head, and the old value of the head isn't empty...
269 */
270 - sprintf(display, _("! %-*s %-*s -> %s (can't fetch in current branch)"),
271 - TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), REFCOL_WIDTH, remote,
272 - pretty_ref);
270 + strbuf_addf(display,
271 + _("! %-*s %-*s -> %s (can't fetch in current branch)"),
272 + TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
273 + REFCOL_WIDTH, remote, pretty_ref);
274 return 1;
275 }
276
@@ -277,9 +278,11 @@ static int update_local_ref(struct ref *ref,
278 !prefixcmp(ref->name, "refs/tags/")) {
279 int r;
280 r = s_update_ref("updating tag", ref, 0);
280 - sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-',
281 - TRANSPORT_SUMMARY_WIDTH, _("[tag update]"), REFCOL_WIDTH, remote,
282 - pretty_ref, r ? _(" (unable to update local ref)") : "");
281 + strbuf_addf(display, "%c %-*s %-*s -> %s%s",
282 + r ? '!' : '-',
283 + TRANSPORT_SUMMARY_WIDTH, _("[tag update]"),
284 + REFCOL_WIDTH, remote, pretty_ref,
285 + r ? _(" (unable to update local ref)") : "");
286 return r;
287 }
288
@@ -302,9 +305,11 @@ static int update_local_ref(struct ref *ref,
305 }
306
307 r = s_update_ref(msg, ref, 0);
305 - sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*',
306 - TRANSPORT_SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref,
307 - r ? _(" (unable to update local ref)") : "");
308 + strbuf_addf(display, "%c %-*s %-*s -> %s%s",
309 + r ? '!' : '*',
310 + TRANSPORT_SUMMARY_WIDTH, what,
311 + REFCOL_WIDTH, remote, pretty_ref,
312 + r ? _(" (unable to update local ref)") : "");
313 return r;
314 }
315
@@ -318,9 +323,11 @@ static int update_local_ref(struct ref *ref,
323 (recurse_submodules != RECURSE_SUBMODULES_ON))
324 check_for_new_submodule_commits(ref->new_sha1);
325 r = s_update_ref("fast-forward", ref, 1);
321 - sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ',
322 - TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
323 - pretty_ref, r ? _(" (unable to update local ref)") : "");
326 + strbuf_addf(display, "%c %-*s %-*s -> %s%s",
327 + r ? '!' : ' ',
328 + TRANSPORT_SUMMARY_WIDTH, quickref,
329 + REFCOL_WIDTH, remote, pretty_ref,
330 + r ? _(" (unable to update local ref)") : "");
331 return r;
332 } else if (force || ref->force) {
333 char quickref[84];
@@ -332,15 +339,17 @@ static int update_local_ref(struct ref *ref,
339 (recurse_submodules != RECURSE_SUBMODULES_ON))
340 check_for_new_submodule_commits(ref->new_sha1);
341 r = s_update_ref("forced-update", ref, 1);
335 - sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+',
336 - TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
337 - pretty_ref,
338 - r ? _("unable to update local ref") : _("forced update"));
342 + strbuf_addf(display, "%c %-*s %-*s -> %s (%s)",
343 + r ? '!' : '+',
344 + TRANSPORT_SUMMARY_WIDTH, quickref,
345 + REFCOL_WIDTH, remote, pretty_ref,
346 + r ? _("unable to update local ref") : _("forced update"));
347 return r;
348 } else {
341 - sprintf(display, "! %-*s %-*s -> %s %s",
342 - TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), REFCOL_WIDTH, remote,
343 - pretty_ref, _("(non-fast-forward)"));
349 + strbuf_addf(display, "! %-*s %-*s -> %s %s",
350 + TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
351 + REFCOL_WIDTH, remote, pretty_ref,
352 + _("(non-fast-forward)"));
353 return 1;
354 }
355 }
@@ -350,8 +359,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
359 {
360 FILE *fp;
361 struct commit *commit;
353 - int url_len, i, note_len, shown_url = 0, rc = 0;
354 - char note[1024];
362 + int url_len, i, shown_url = 0, rc = 0;
363 + struct strbuf note = STRBUF_INIT;
364 const char *what, *kind;
365 struct ref *rm;
366 char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD");
@@ -407,19 +416,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
416 if (4 < i && !strncmp(".git", url + i - 3, 4))
417 url_len = i - 3;
418
410 - note_len = 0;
419 + strbuf_reset(&note);
420 if (*what) {
421 if (*kind)
413 - note_len += sprintf(note + note_len, "%s ",
414 - kind);
415 - note_len += sprintf(note + note_len, "'%s' of ", what);
422 + strbuf_addf(&note, "%s ", kind);
423 + strbuf_addf(&note, "'%s' of ", what);
424 }
417 - note[note_len] = '\0';
425 fprintf(fp, "%s\t%s\t%s",
426 sha1_to_hex(commit ? commit->object.sha1 :
427 rm->old_sha1),
428 rm->merge ? "" : "not-for-merge",
422 - note);
429 + note.buf);
430 for (i = 0; i < url_len; ++i)
431 if ('\n' == url[i])
432 fputs("\\n", fp);
@@ -427,21 +434,24 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
434 fputc(url[i], fp);
435 fputc('\n', fp);
436
437 + strbuf_reset(&note);
438 if (ref) {
431 - rc |= update_local_ref(ref, what, note);
439 + rc |= update_local_ref(ref, what, &note);
440 free(ref);
441 } else
434 - sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
435 - TRANSPORT_SUMMARY_WIDTH, *kind ? kind : "branch",
436 - REFCOL_WIDTH, *what ? what : "HEAD");
437 - if (*note) {
442 + strbuf_addf(&note, "* %-*s %-*s -> FETCH_HEAD",
443 + TRANSPORT_SUMMARY_WIDTH,
444 + *kind ? kind : "branch",
445 + REFCOL_WIDTH,
446 + *what ? what : "HEAD");
447 + if (note.len) {
448 if (verbosity >= 0 && !shown_url) {
449 fprintf(stderr, _("From %.*s\n"),
450 url_len, url);
451 shown_url = 1;
452 }
453 if (verbosity >= 0)
444 - fprintf(stderr, " %s\n", note);
454 + fprintf(stderr, " %s\n", note.buf);
455 }
456 }
457 free(url);
@@ -450,6 +460,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
460 error(_("some local refs could not be updated; try running\n"
461 " 'git remote prune %s' to remove any old, conflicting "
462 "branches"), remote_name);
463 + strbuf_release(&note);
464 return rc;
465 }
466