Skip to content

Commit fc1a3f4

Browse files
committed
object: return GIT_EINVALID on parse errors
Return `GIT_EINVALID` on parse errors so that direct callers of parse functions can determine when there was a failure to parse the object. The object parser functions will swallow this error code to prevent it from propagating down the chain to end-users. (`git_merge` should not return `GIT_EINVALID` when a commit it tries to look up is not valid, this would be too vague to be useful.) The only public function that this affects is `git_signature_from_buffer`, which is now documented as returning `GIT_EINVALID` when appropriate.
1 parent 6fdb1b2 commit fc1a3f4

File tree

8 files changed

+69
-39
lines changed

8 files changed

+69
-39
lines changed

include/git2/signature.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ GIT_EXTERN(int) git_signature_default(git_signature **out, git_repository *repo)
7171
*
7272
* @param out new signature
7373
* @param buf signature string
74-
* @return 0 on success, or an error code
74+
* @return 0 on success, GIT_EINVALID if the signature is not parseable, or an error code
7575
*/
7676
GIT_EXTERN(int) git_signature_from_buffer(git_signature **out, const char *buf);
7777

src/commit.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
395395
git_oid parent_id;
396396
size_t header_len;
397397
git_signature dummy_sig;
398+
int error;
398399

399400
GIT_ASSERT_ARG(commit);
400401
GIT_ASSERT_ARG(data);
@@ -431,14 +432,14 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
431432
commit->author = git__malloc(sizeof(git_signature));
432433
GIT_ERROR_CHECK_ALLOC(commit->author);
433434

434-
if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0)
435-
return -1;
435+
if ((error = git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n')) < 0)
436+
return error;
436437
}
437438

438439
/* Some tools create multiple author fields, ignore the extra ones */
439440
while (!git__prefixncmp(buffer, buffer_end - buffer, "author ")) {
440-
if (git_signature__parse(&dummy_sig, &buffer, buffer_end, "author ", '\n') < 0)
441-
return -1;
441+
if ((error = git_signature__parse(&dummy_sig, &buffer, buffer_end, "author ", '\n')) < 0)
442+
return error;
442443

443444
git__free(dummy_sig.name);
444445
git__free(dummy_sig.email);
@@ -448,8 +449,8 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
448449
commit->committer = git__malloc(sizeof(git_signature));
449450
GIT_ERROR_CHECK_ALLOC(commit->committer);
450451

451-
if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0)
452-
return -1;
452+
if ((error = git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n')) < 0)
453+
return error;
453454

454455
if (flags & GIT_COMMIT_PARSE_QUICK)
455456
return 0;
@@ -493,7 +494,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
493494

494495
bad_buffer:
495496
git_error_set(GIT_ERROR_OBJECT, "failed to parse bad commit object");
496-
return -1;
497+
return GIT_EINVALID;
497498
}
498499

499500
int git_commit__parse_raw(void *commit, const char *data, size_t size)
@@ -971,8 +972,10 @@ int git_commit_create_with_signature(
971972
/* The first step is to verify that all the tree and parents exist */
972973
parsed = git__calloc(1, sizeof(git_commit));
973974
GIT_ERROR_CHECK_ALLOC(parsed);
974-
if ((error = commit_parse(parsed, commit_content, strlen(commit_content), 0)) < 0)
975+
if (commit_parse(parsed, commit_content, strlen(commit_content), 0) < 0) {
976+
error = -1;
975977
goto cleanup;
978+
}
976979

977980
if ((error = validate_tree_and_parents(&parents, repo, &parsed->tree_id, commit_parent_from_commit, parsed, NULL, true)) < 0)
978981
goto cleanup;

src/commit_list.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,16 +124,15 @@ static int commit_quick_parse(
124124
{
125125
git_oid *parent_oid;
126126
git_commit *commit;
127-
int error;
128127
size_t i;
129128

130129
commit = git__calloc(1, sizeof(*commit));
131130
GIT_ERROR_CHECK_ALLOC(commit);
132131
commit->object.repo = walk->repo;
133132

134-
if ((error = git_commit__parse_ext(commit, obj, GIT_COMMIT_PARSE_QUICK)) < 0) {
133+
if (git_commit__parse_ext(commit, obj, GIT_COMMIT_PARSE_QUICK) < 0) {
135134
git__free(commit);
136-
return error;
135+
return -1;
137136
}
138137

139138
if (!git__is_uint16(git_array_size(commit->parent_ids))) {

src/indexer.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,16 +340,22 @@ static int check_object_connectivity(git_indexer *idx, const git_rawobj *obj)
340340
{
341341
git_object *object;
342342
git_oid *expected;
343-
int error;
343+
int error = 0;
344344

345345
if (obj->type != GIT_OBJECT_BLOB &&
346346
obj->type != GIT_OBJECT_TREE &&
347347
obj->type != GIT_OBJECT_COMMIT &&
348348
obj->type != GIT_OBJECT_TAG)
349349
return 0;
350350

351-
if ((error = git_object__from_raw(&object, obj->data, obj->len, obj->type)) < 0)
351+
if (git_object__from_raw(&object, obj->data, obj->len, obj->type) < 0) {
352+
/*
353+
* parse_raw returns EINVALID on invalid data; downgrade
354+
* that to a normal -1 error code.
355+
*/
356+
error = -1;
352357
goto out;
358+
}
353359

354360
if ((expected = git_oidmap_get(idx->expected_oids, &object->cached.oid)) != NULL) {
355361
git_oidmap_delete(idx->expected_oids, &object->cached.oid);

src/object.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,17 @@ int git_object__from_odb_object(
144144
def = &git_objects_table[odb_obj->cached.type];
145145
GIT_ASSERT(def->free && def->parse);
146146

147-
if ((error = def->parse(object, odb_obj)) < 0)
147+
if ((error = def->parse(object, odb_obj)) < 0) {
148+
/*
149+
* parse returns EINVALID on invalid data; downgrade
150+
* that to a normal -1 error code.
151+
*/
148152
def->free(object);
149-
else
150-
*object_out = git_cache_store_parsed(&repo->objects, object);
153+
return -1;
154+
}
151155

152-
return error;
156+
*object_out = git_cache_store_parsed(&repo->objects, object);
157+
return 0;
153158
}
154159

155160
void git_object__free(void *obj)

src/signature.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ void git_signature_free(git_signature *sig)
2323
git__free(sig);
2424
}
2525

26+
static int signature_parse_error(const char *msg)
27+
{
28+
git_error_set(GIT_ERROR_INVALID, "failed to parse signature - %s", msg);
29+
return GIT_EINVALID;
30+
}
31+
2632
static int signature_error(const char *msg)
2733
{
2834
git_error_set(GIT_ERROR_INVALID, "failed to parse signature - %s", msg);
@@ -206,13 +212,13 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
206212

207213
if (ender &&
208214
(buffer_end = memchr(buffer, ender, buffer_end - buffer)) == NULL)
209-
return signature_error("no newline given");
215+
return signature_parse_error("no newline given");
210216

211217
if (header) {
212218
const size_t header_len = strlen(header);
213219

214220
if (buffer + header_len >= buffer_end || memcmp(buffer, header, header_len) != 0)
215-
return signature_error("expected prefix doesn't match actual");
221+
return signature_parse_error("expected prefix doesn't match actual");
216222

217223
buffer += header_len;
218224
}
@@ -221,7 +227,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
221227
email_end = git__memrchr(buffer, '>', buffer_end - buffer);
222228

223229
if (!email_start || !email_end || email_end <= email_start)
224-
return signature_error("malformed e-mail");
230+
return signature_parse_error("malformed e-mail");
225231

226232
email_start += 1;
227233
sig->name = extract_trimmed(buffer, email_start - buffer - 1);
@@ -237,7 +243,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
237243
git__free(sig->name);
238244
git__free(sig->email);
239245
sig->name = sig->email = NULL;
240-
return signature_error("invalid Unix timestamp");
246+
return signature_parse_error("invalid Unix timestamp");
241247
}
242248

243249
/* do we have a timezone? */

src/tag.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const char *git_tag_message(const git_tag *t)
6262
static int tag_error(const char *str)
6363
{
6464
git_error_set(GIT_ERROR_TAG, "failed to parse tag: %s", str);
65-
return -1;
65+
return GIT_EINVALID;
6666
}
6767

6868
static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
@@ -73,6 +73,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
7373
size_t text_len, alloc_len;
7474
const char *search;
7575
unsigned int i;
76+
int error;
7677

7778
if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0)
7879
return tag_error("object field invalid");
@@ -130,8 +131,8 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
130131
tag->tagger = git__malloc(sizeof(git_signature));
131132
GIT_ERROR_CHECK_ALLOC(tag->tagger);
132133

133-
if (git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n') < 0)
134-
return -1;
134+
if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ", '\n')) < 0)
135+
return error;
135136
}
136137

137138
tag->message = NULL;

src/tree.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -351,15 +351,26 @@ size_t git_treebuilder_entrycount(git_treebuilder *bld)
351351
return git_strmap_size(bld->map);
352352
}
353353

354-
static int tree_error(const char *str, const char *path)
354+
GIT_INLINE(void) set_error(const char *str, const char *path)
355355
{
356356
if (path)
357357
git_error_set(GIT_ERROR_TREE, "%s - %s", str, path);
358358
else
359359
git_error_set(GIT_ERROR_TREE, "%s", str);
360+
}
361+
362+
static int tree_error(const char *str, const char *path)
363+
{
364+
set_error(str, path);
360365
return -1;
361366
}
362367

368+
static int tree_parse_error(const char *str, const char *path)
369+
{
370+
set_error(str, path);
371+
return GIT_EINVALID;
372+
}
373+
363374
static int parse_mode(uint16_t *mode_out, const char *buffer, size_t buffer_len, const char **buffer_out)
364375
{
365376
int32_t mode;
@@ -399,19 +410,19 @@ int git_tree__parse_raw(void *_tree, const char *data, size_t size)
399410
uint16_t attr;
400411

401412
if (parse_mode(&attr, buffer, buffer_end - buffer, &buffer) < 0 || !buffer)
402-
return tree_error("failed to parse tree: can't parse filemode", NULL);
413+
return tree_parse_error("failed to parse tree: can't parse filemode", NULL);
403414

404415
if (buffer >= buffer_end || (*buffer++) != ' ')
405-
return tree_error("failed to parse tree: missing space after filemode", NULL);
416+
return tree_parse_error("failed to parse tree: missing space after filemode", NULL);
406417

407418
if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL)
408-
return tree_error("failed to parse tree: object is corrupted", NULL);
419+
return tree_parse_error("failed to parse tree: object is corrupted", NULL);
409420

410421
if ((filename_len = nul - buffer) == 0 || filename_len > UINT16_MAX)
411-
return tree_error("failed to parse tree: can't parse filename", NULL);
422+
return tree_parse_error("failed to parse tree: can't parse filename", NULL);
412423

413424
if ((buffer_end - (nul + 1)) < GIT_OID_RAWSZ)
414-
return tree_error("failed to parse tree: can't parse OID", NULL);
425+
return tree_parse_error("failed to parse tree: can't parse OID", NULL);
415426

416427
/* Allocate the entry */
417428
{
@@ -434,16 +445,15 @@ int git_tree__parse_raw(void *_tree, const char *data, size_t size)
434445
int git_tree__parse(void *_tree, git_odb_object *odb_obj)
435446
{
436447
git_tree *tree = _tree;
448+
const char *data = git_odb_object_data(odb_obj);
449+
size_t size = git_odb_object_size(odb_obj);
450+
int error;
437451

438-
if ((git_tree__parse_raw(tree,
439-
git_odb_object_data(odb_obj),
440-
git_odb_object_size(odb_obj))) < 0)
441-
return -1;
442-
443-
if (git_odb_object_dup(&tree->odb_obj, odb_obj) < 0)
444-
return -1;
452+
if ((error = git_tree__parse_raw(tree, data, size)) < 0 ||
453+
(error = git_odb_object_dup(&tree->odb_obj, odb_obj)) < 0)
454+
return error;
445455

446-
return 0;
456+
return error;
447457
}
448458

449459
static size_t find_next_dir(const char *dirname, git_index *index, size_t start)

0 commit comments

Comments
 (0)