Skip to content

Commit bc2fed4

Browse files
trastgitster
authored andcommitted
bundle: use a strbuf to scan the log for boundary commits
The first part of the bundle header contains the boundary commits, and could be approximated by # v2 git bundle $(git rev-list --pretty=oneline --boundary <ARGS> | grep ^-) git-bundle actually spawns exactly this rev-list invocation, and does the grepping internally. There was a subtle bug in the latter step: it used fgets() with a 1024-byte buffer. If the user has sufficiently long subjects (e.g., by not adhering to the git oneline-subject convention in the first place), the 'oneline' format can easily overflow the buffer. fgets() then returns the rest of the line in the next call(s). If one of these remaining parts started with '-', git-bundle would mistakenly insert it into the bundle thinking it was a boundary commit. Fix it by using strbuf_getwholeline() instead, which handles arbitrary line lengths correctly. Note that on the receiving side in parse_bundle_header() we were already using strbuf_getwholeline_fd(), so that part is safe. Reported-by: Jannis Pohlmann <[email protected]> Signed-off-by: Thomas Rast <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5e8617f commit bc2fed4

File tree

2 files changed

+24
-7
lines changed

2 files changed

+24
-7
lines changed

bundle.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ int create_bundle(struct bundle_header *header, const char *path,
234234
const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *));
235235
const char **argv_pack = xmalloc(6 * sizeof(const char *));
236236
int i, ref_count = 0;
237-
char buffer[1024];
237+
struct strbuf buf = STRBUF_INIT;
238238
struct rev_info revs;
239239
struct child_process rls;
240240
FILE *rls_fout;
@@ -266,20 +266,21 @@ int create_bundle(struct bundle_header *header, const char *path,
266266
if (start_command(&rls))
267267
return -1;
268268
rls_fout = xfdopen(rls.out, "r");
269-
while (fgets(buffer, sizeof(buffer), rls_fout)) {
269+
while (strbuf_getwholeline(&buf, rls_fout, '\n') != EOF) {
270270
unsigned char sha1[20];
271-
if (buffer[0] == '-') {
272-
write_or_die(bundle_fd, buffer, strlen(buffer));
273-
if (!get_sha1_hex(buffer + 1, sha1)) {
271+
if (buf.len > 0 && buf.buf[0] == '-') {
272+
write_or_die(bundle_fd, buf.buf, buf.len);
273+
if (!get_sha1_hex(buf.buf + 1, sha1)) {
274274
struct object *object = parse_object(sha1);
275275
object->flags |= UNINTERESTING;
276-
add_pending_object(&revs, object, buffer);
276+
add_pending_object(&revs, object, buf.buf);
277277
}
278-
} else if (!get_sha1_hex(buffer, sha1)) {
278+
} else if (!get_sha1_hex(buf.buf, sha1)) {
279279
struct object *object = parse_object(sha1);
280280
object->flags |= SHOWN;
281281
}
282282
}
283+
strbuf_release(&buf);
283284
fclose(rls_fout);
284285
if (finish_command(&rls))
285286
return error("rev-list died");

t/t5704-bundle.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,20 @@ test_expect_success 'empty bundle file is rejected' '
5959
6060
'
6161

62+
# This triggers a bug in older versions where the resulting line (with
63+
# --pretty=oneline) was longer than a 1024-char buffer.
64+
test_expect_success 'ridiculously long subject in boundary' '
65+
: >file4 &&
66+
test_tick &&
67+
git add file4 &&
68+
printf "%01200d\n" 0 | git commit -F - &&
69+
test_commit fifth &&
70+
git bundle create long-subject-bundle.bdl HEAD^..HEAD &&
71+
git bundle list-heads long-subject-bundle.bdl >heads &&
72+
test -s heads &&
73+
git fetch long-subject-bundle.bdl &&
74+
sed -n "/^-/{p;q}" long-subject-bundle.bdl >boundary &&
75+
grep "^-$_x40 " boundary
76+
'
77+
6278
test_done

0 commit comments

Comments
 (0)