Skip to content

Commit b9f0662

Browse files
committed
Merge branch 'pw/fast-import-dataref-parsing' into maint
The parser in "fast-import" did not diagnose ":9" style references that is not followed by required SP/LF as an error. By Pete Wyckoff * pw/fast-import-dataref-parsing: fast-import: tighten parsing of datarefs
2 parents cda03b6 + 06454cb commit b9f0662

File tree

2 files changed

+364
-33
lines changed

2 files changed

+364
-33
lines changed

fast-import.c

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,6 +2207,59 @@ static uintmax_t change_note_fanout(struct tree_entry *root,
22072207
return do_change_note_fanout(root, root, hex_sha1, 0, path, 0, fanout);
22082208
}
22092209

2210+
/*
2211+
* Given a pointer into a string, parse a mark reference:
2212+
*
2213+
* idnum ::= ':' bigint;
2214+
*
2215+
* Return the first character after the value in *endptr.
2216+
*
2217+
* Complain if the following character is not what is expected,
2218+
* either a space or end of the string.
2219+
*/
2220+
static uintmax_t parse_mark_ref(const char *p, char **endptr)
2221+
{
2222+
uintmax_t mark;
2223+
2224+
assert(*p == ':');
2225+
p++;
2226+
mark = strtoumax(p, endptr, 10);
2227+
if (*endptr == p)
2228+
die("No value after ':' in mark: %s", command_buf.buf);
2229+
return mark;
2230+
}
2231+
2232+
/*
2233+
* Parse the mark reference, and complain if this is not the end of
2234+
* the string.
2235+
*/
2236+
static uintmax_t parse_mark_ref_eol(const char *p)
2237+
{
2238+
char *end;
2239+
uintmax_t mark;
2240+
2241+
mark = parse_mark_ref(p, &end);
2242+
if (*end != '\0')
2243+
die("Garbage after mark: %s", command_buf.buf);
2244+
return mark;
2245+
}
2246+
2247+
/*
2248+
* Parse the mark reference, demanding a trailing space. Return a
2249+
* pointer to the space.
2250+
*/
2251+
static uintmax_t parse_mark_ref_space(const char **p)
2252+
{
2253+
uintmax_t mark;
2254+
char *end;
2255+
2256+
mark = parse_mark_ref(*p, &end);
2257+
if (*end != ' ')
2258+
die("Missing space after mark: %s", command_buf.buf);
2259+
*p = end;
2260+
return mark;
2261+
}
2262+
22102263
static void file_change_m(struct branch *b)
22112264
{
22122265
const char *p = command_buf.buf + 2;
@@ -2235,21 +2288,21 @@ static void file_change_m(struct branch *b)
22352288
}
22362289

22372290
if (*p == ':') {
2238-
char *x;
2239-
oe = find_mark(strtoumax(p + 1, &x, 10));
2291+
oe = find_mark(parse_mark_ref_space(&p));
22402292
hashcpy(sha1, oe->idx.sha1);
2241-
p = x;
2242-
} else if (!prefixcmp(p, "inline")) {
2293+
} else if (!prefixcmp(p, "inline ")) {
22432294
inline_data = 1;
2244-
p += 6;
2295+
p += strlen("inline"); /* advance to space */
22452296
} else {
22462297
if (get_sha1_hex(p, sha1))
2247-
die("Invalid SHA1: %s", command_buf.buf);
2298+
die("Invalid dataref: %s", command_buf.buf);
22482299
oe = find_object(sha1);
22492300
p += 40;
2301+
if (*p != ' ')
2302+
die("Missing space after SHA1: %s", command_buf.buf);
22502303
}
2251-
if (*p++ != ' ')
2252-
die("Missing space after SHA1: %s", command_buf.buf);
2304+
assert(*p == ' ');
2305+
p++; /* skip space */
22532306

22542307
strbuf_reset(&uq);
22552308
if (!unquote_c_style(&uq, p, &endp)) {
@@ -2407,21 +2460,21 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
24072460
/* Now parse the notemodify command. */
24082461
/* <dataref> or 'inline' */
24092462
if (*p == ':') {
2410-
char *x;
2411-
oe = find_mark(strtoumax(p + 1, &x, 10));
2463+
oe = find_mark(parse_mark_ref_space(&p));
24122464
hashcpy(sha1, oe->idx.sha1);
2413-
p = x;
2414-
} else if (!prefixcmp(p, "inline")) {
2465+
} else if (!prefixcmp(p, "inline ")) {
24152466
inline_data = 1;
2416-
p += 6;
2467+
p += strlen("inline"); /* advance to space */
24172468
} else {
24182469
if (get_sha1_hex(p, sha1))
2419-
die("Invalid SHA1: %s", command_buf.buf);
2470+
die("Invalid dataref: %s", command_buf.buf);
24202471
oe = find_object(sha1);
24212472
p += 40;
2473+
if (*p != ' ')
2474+
die("Missing space after SHA1: %s", command_buf.buf);
24222475
}
2423-
if (*p++ != ' ')
2424-
die("Missing space after SHA1: %s", command_buf.buf);
2476+
assert(*p == ' ');
2477+
p++; /* skip space */
24252478

24262479
/* <committish> */
24272480
s = lookup_branch(p);
@@ -2430,7 +2483,7 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
24302483
die("Can't add a note on empty branch.");
24312484
hashcpy(commit_sha1, s->sha1);
24322485
} else if (*p == ':') {
2433-
uintmax_t commit_mark = strtoumax(p + 1, NULL, 10);
2486+
uintmax_t commit_mark = parse_mark_ref_eol(p);
24342487
struct object_entry *commit_oe = find_mark(commit_mark);
24352488
if (commit_oe->type != OBJ_COMMIT)
24362489
die("Mark :%" PRIuMAX " not a commit", commit_mark);
@@ -2537,7 +2590,7 @@ static int parse_from(struct branch *b)
25372590
hashcpy(b->branch_tree.versions[0].sha1, t);
25382591
hashcpy(b->branch_tree.versions[1].sha1, t);
25392592
} else if (*from == ':') {
2540-
uintmax_t idnum = strtoumax(from + 1, NULL, 10);
2593+
uintmax_t idnum = parse_mark_ref_eol(from);
25412594
struct object_entry *oe = find_mark(idnum);
25422595
if (oe->type != OBJ_COMMIT)
25432596
die("Mark :%" PRIuMAX " not a commit", idnum);
@@ -2572,7 +2625,7 @@ static struct hash_list *parse_merge(unsigned int *count)
25722625
if (s)
25732626
hashcpy(n->sha1, s->sha1);
25742627
else if (*from == ':') {
2575-
uintmax_t idnum = strtoumax(from + 1, NULL, 10);
2628+
uintmax_t idnum = parse_mark_ref_eol(from);
25762629
struct object_entry *oe = find_mark(idnum);
25772630
if (oe->type != OBJ_COMMIT)
25782631
die("Mark :%" PRIuMAX " not a commit", idnum);
@@ -2735,7 +2788,7 @@ static void parse_new_tag(void)
27352788
type = OBJ_COMMIT;
27362789
} else if (*from == ':') {
27372790
struct object_entry *oe;
2738-
from_mark = strtoumax(from + 1, NULL, 10);
2791+
from_mark = parse_mark_ref_eol(from);
27392792
oe = find_mark(from_mark);
27402793
type = oe->type;
27412794
hashcpy(sha1, oe->idx.sha1);
@@ -2867,18 +2920,13 @@ static void parse_cat_blob(void)
28672920
/* cat-blob SP <object> LF */
28682921
p = command_buf.buf + strlen("cat-blob ");
28692922
if (*p == ':') {
2870-
char *x;
2871-
oe = find_mark(strtoumax(p + 1, &x, 10));
2872-
if (x == p + 1)
2873-
die("Invalid mark: %s", command_buf.buf);
2923+
oe = find_mark(parse_mark_ref_eol(p));
28742924
if (!oe)
28752925
die("Unknown mark: %s", command_buf.buf);
2876-
if (*x)
2877-
die("Garbage after mark: %s", command_buf.buf);
28782926
hashcpy(sha1, oe->idx.sha1);
28792927
} else {
28802928
if (get_sha1_hex(p, sha1))
2881-
die("Invalid SHA1: %s", command_buf.buf);
2929+
die("Invalid dataref: %s", command_buf.buf);
28822930
if (p[40])
28832931
die("Garbage after SHA1: %s", command_buf.buf);
28842932
oe = find_object(sha1);
@@ -2944,17 +2992,13 @@ static struct object_entry *parse_treeish_dataref(const char **p)
29442992
struct object_entry *e;
29452993

29462994
if (**p == ':') { /* <mark> */
2947-
char *endptr;
2948-
e = find_mark(strtoumax(*p + 1, &endptr, 10));
2949-
if (endptr == *p + 1)
2950-
die("Invalid mark: %s", command_buf.buf);
2995+
e = find_mark(parse_mark_ref_space(p));
29512996
if (!e)
29522997
die("Unknown mark: %s", command_buf.buf);
2953-
*p = endptr;
29542998
hashcpy(sha1, e->idx.sha1);
29552999
} else { /* <sha1> */
29563000
if (get_sha1_hex(*p, sha1))
2957-
die("Invalid SHA1: %s", command_buf.buf);
3001+
die("Invalid dataref: %s", command_buf.buf);
29583002
e = find_object(sha1);
29593003
*p += 40;
29603004
}

0 commit comments

Comments
 (0)