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>
This commit is contained in:
Jeff King 2011-12-08 03:43:19 -05:00 committed by Junio C Hamano
parent 69d61daec7
commit 5914f2d057

View File

@ -239,23 +239,23 @@ static int s_update_ref(const char *action,
static int update_local_ref(struct ref *ref, static int update_local_ref(struct ref *ref,
const char *remote, const char *remote,
char *display) struct strbuf *display)
{ {
struct commit *current = NULL, *updated; struct commit *current = NULL, *updated;
enum object_type type; enum object_type type;
struct branch *current_branch = branch_get(NULL); struct branch *current_branch = branch_get(NULL);
const char *pretty_ref = prettify_refname(ref->name); const char *pretty_ref = prettify_refname(ref->name);
*display = 0;
type = sha1_object_info(ref->new_sha1, NULL); type = sha1_object_info(ref->new_sha1, NULL);
if (type < 0) if (type < 0)
die(_("object %s not found"), sha1_to_hex(ref->new_sha1)); die(_("object %s not found"), sha1_to_hex(ref->new_sha1));
if (!hashcmp(ref->old_sha1, ref->new_sha1)) { if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
if (verbosity > 0) if (verbosity > 0)
sprintf(display, "= %-*s %-*s -> %s", TRANSPORT_SUMMARY_WIDTH, strbuf_addf(display, "= %-*s %-*s -> %s",
_("[up to date]"), REFCOL_WIDTH, remote, TRANSPORT_SUMMARY_WIDTH,
pretty_ref); _("[up to date]"), REFCOL_WIDTH,
remote, pretty_ref);
return 0; return 0;
} }
@ -267,9 +267,10 @@ static int update_local_ref(struct ref *ref,
* If this is the head, and it's not okay to update * If this is the head, and it's not okay to update
* the head, and the old value of the head isn't empty... * the head, and the old value of the head isn't empty...
*/ */
sprintf(display, _("! %-*s %-*s -> %s (can't fetch in current branch)"), strbuf_addf(display,
TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), REFCOL_WIDTH, remote, _("! %-*s %-*s -> %s (can't fetch in current branch)"),
pretty_ref); TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
REFCOL_WIDTH, remote, pretty_ref);
return 1; return 1;
} }
@ -277,9 +278,11 @@ static int update_local_ref(struct ref *ref,
!prefixcmp(ref->name, "refs/tags/")) { !prefixcmp(ref->name, "refs/tags/")) {
int r; int r;
r = s_update_ref("updating tag", ref, 0); r = s_update_ref("updating tag", ref, 0);
sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-', strbuf_addf(display, "%c %-*s %-*s -> %s%s",
TRANSPORT_SUMMARY_WIDTH, _("[tag update]"), REFCOL_WIDTH, remote, r ? '!' : '-',
pretty_ref, r ? _(" (unable to update local ref)") : ""); TRANSPORT_SUMMARY_WIDTH, _("[tag update]"),
REFCOL_WIDTH, remote, pretty_ref,
r ? _(" (unable to update local ref)") : "");
return r; return r;
} }
@ -302,8 +305,10 @@ static int update_local_ref(struct ref *ref,
} }
r = s_update_ref(msg, ref, 0); r = s_update_ref(msg, ref, 0);
sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*', strbuf_addf(display, "%c %-*s %-*s -> %s%s",
TRANSPORT_SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref, r ? '!' : '*',
TRANSPORT_SUMMARY_WIDTH, what,
REFCOL_WIDTH, remote, pretty_ref,
r ? _(" (unable to update local ref)") : ""); r ? _(" (unable to update local ref)") : "");
return r; return r;
} }
@ -318,9 +323,11 @@ static int update_local_ref(struct ref *ref,
(recurse_submodules != RECURSE_SUBMODULES_ON)) (recurse_submodules != RECURSE_SUBMODULES_ON))
check_for_new_submodule_commits(ref->new_sha1); check_for_new_submodule_commits(ref->new_sha1);
r = s_update_ref("fast-forward", ref, 1); r = s_update_ref("fast-forward", ref, 1);
sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ', strbuf_addf(display, "%c %-*s %-*s -> %s%s",
TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, r ? '!' : ' ',
pretty_ref, r ? _(" (unable to update local ref)") : ""); TRANSPORT_SUMMARY_WIDTH, quickref,
REFCOL_WIDTH, remote, pretty_ref,
r ? _(" (unable to update local ref)") : "");
return r; return r;
} else if (force || ref->force) { } else if (force || ref->force) {
char quickref[84]; char quickref[84];
@ -332,15 +339,17 @@ static int update_local_ref(struct ref *ref,
(recurse_submodules != RECURSE_SUBMODULES_ON)) (recurse_submodules != RECURSE_SUBMODULES_ON))
check_for_new_submodule_commits(ref->new_sha1); check_for_new_submodule_commits(ref->new_sha1);
r = s_update_ref("forced-update", ref, 1); r = s_update_ref("forced-update", ref, 1);
sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+', strbuf_addf(display, "%c %-*s %-*s -> %s (%s)",
TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, r ? '!' : '+',
pretty_ref, TRANSPORT_SUMMARY_WIDTH, quickref,
REFCOL_WIDTH, remote, pretty_ref,
r ? _("unable to update local ref") : _("forced update")); r ? _("unable to update local ref") : _("forced update"));
return r; return r;
} else { } else {
sprintf(display, "! %-*s %-*s -> %s %s", strbuf_addf(display, "! %-*s %-*s -> %s %s",
TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), REFCOL_WIDTH, remote, TRANSPORT_SUMMARY_WIDTH, _("[rejected]"),
pretty_ref, _("(non-fast-forward)")); REFCOL_WIDTH, remote, pretty_ref,
_("(non-fast-forward)"));
return 1; return 1;
} }
} }
@ -350,8 +359,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
{ {
FILE *fp; FILE *fp;
struct commit *commit; struct commit *commit;
int url_len, i, note_len, shown_url = 0, rc = 0; int url_len, i, shown_url = 0, rc = 0;
char note[1024]; struct strbuf note = STRBUF_INIT;
const char *what, *kind; const char *what, *kind;
struct ref *rm; struct ref *rm;
char *url, *filename = dry_run ? "/dev/null" : git_path("FETCH_HEAD"); 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,
if (4 < i && !strncmp(".git", url + i - 3, 4)) if (4 < i && !strncmp(".git", url + i - 3, 4))
url_len = i - 3; url_len = i - 3;
note_len = 0; strbuf_reset(&note);
if (*what) { if (*what) {
if (*kind) if (*kind)
note_len += sprintf(note + note_len, "%s ", strbuf_addf(&note, "%s ", kind);
kind); strbuf_addf(&note, "'%s' of ", what);
note_len += sprintf(note + note_len, "'%s' of ", what);
} }
note[note_len] = '\0';
fprintf(fp, "%s\t%s\t%s", fprintf(fp, "%s\t%s\t%s",
sha1_to_hex(commit ? commit->object.sha1 : sha1_to_hex(commit ? commit->object.sha1 :
rm->old_sha1), rm->old_sha1),
rm->merge ? "" : "not-for-merge", rm->merge ? "" : "not-for-merge",
note); note.buf);
for (i = 0; i < url_len; ++i) for (i = 0; i < url_len; ++i)
if ('\n' == url[i]) if ('\n' == url[i])
fputs("\\n", fp); fputs("\\n", fp);
@ -427,21 +434,24 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
fputc(url[i], fp); fputc(url[i], fp);
fputc('\n', fp); fputc('\n', fp);
strbuf_reset(&note);
if (ref) { if (ref) {
rc |= update_local_ref(ref, what, note); rc |= update_local_ref(ref, what, &note);
free(ref); free(ref);
} else } else
sprintf(note, "* %-*s %-*s -> FETCH_HEAD", strbuf_addf(&note, "* %-*s %-*s -> FETCH_HEAD",
TRANSPORT_SUMMARY_WIDTH, *kind ? kind : "branch", TRANSPORT_SUMMARY_WIDTH,
REFCOL_WIDTH, *what ? what : "HEAD"); *kind ? kind : "branch",
if (*note) { REFCOL_WIDTH,
*what ? what : "HEAD");
if (note.len) {
if (verbosity >= 0 && !shown_url) { if (verbosity >= 0 && !shown_url) {
fprintf(stderr, _("From %.*s\n"), fprintf(stderr, _("From %.*s\n"),
url_len, url); url_len, url);
shown_url = 1; shown_url = 1;
} }
if (verbosity >= 0) if (verbosity >= 0)
fprintf(stderr, " %s\n", note); fprintf(stderr, " %s\n", note.buf);
} }
} }
free(url); free(url);
@ -450,6 +460,7 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
error(_("some local refs could not be updated; try running\n" error(_("some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting " " 'git remote prune %s' to remove any old, conflicting "
"branches"), remote_name); "branches"), remote_name);
strbuf_release(&note);
return rc; return rc;
} }