Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9a78665

Browse files
committed
odb: Handle corner cases in git_odb_expand_ids
The old implementation had two issues: 1. OIDs that were too short as to be ambiguous were not being handled properly. 2. If the last OID to expand in the array was missing from the ODB, we would leak a `GIT_ENOTFOUND` error code from the function.
1 parent c68044a commit 9a78665

File tree

2 files changed

+36
-22
lines changed

2 files changed

+36
-22
lines changed

src/odb.c

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -748,54 +748,59 @@ int git_odb_expand_ids(
748748
size_t count)
749749
{
750750
size_t len, i;
751-
int error;
752751

753752
assert(db && ids);
754753

755754
for (i = 0; i < count; i++) {
756755
git_odb_expand_id *query = &ids[i];
757-
git_oid *actual_id = NULL, tmp;
756+
git_oid actual_id;
758757
git_otype query_type = (query->type == GIT_OBJ_ANY) ? 0 : query->type;
759758
git_otype actual_type = 0;
759+
int error = GIT_EAMBIGUOUS;
760760

761761
/* if we were given a full object ID, simply look it up */
762762
if (query->length >= GIT_OID_HEXSZ) {
763763
error = git_odb_read_header(&len, &actual_type, db, &query->id);
764+
git_oid_cpy(&actual_id, &query->id);
764765
}
765766

766-
/* otherwise, resolve the short id to full, then (optionally)
767-
* read the header.
767+
/*
768+
* otherwise, resolve the short id to full if it's long enough, then
769+
* (optionally) read the header
768770
*/
769771
else if (query->length >= GIT_OID_MINPREFIXLEN) {
770-
error = odb_exists_prefix_1(&tmp,
771-
db, &query->id, query->length, false);
772-
773-
if (!error) {
774-
actual_id = &tmp;
775-
error = git_odb_read_header(&len, &actual_type, db, &tmp);
776-
}
772+
error = odb_exists_prefix_1(&actual_id, db, &query->id, query->length, false);
773+
if (!error)
774+
error = git_odb_read_header(&len, &actual_type, db, &actual_id);
777775
}
778776

779-
if (error < 0 && error != GIT_ENOTFOUND && error != GIT_EAMBIGUOUS)
780-
break;
781-
782-
if (error == 0 && (query_type == actual_type || !query_type)) {
783-
if (actual_id)
784-
git_oid_cpy(&query->id, actual_id);
777+
/* Ensure that the looked up type matches the type we were expecting */
778+
if (query_type && query_type != actual_type)
779+
error = GIT_ENOTFOUND;
785780

781+
switch (error) {
782+
case 0:
783+
git_oid_cpy(&query->id, &actual_id);
786784
query->length = GIT_OID_HEXSZ;
787785
query->type = actual_type;
788-
} else {
786+
break;
787+
788+
/* the object is missing or ambiguous */
789+
case GIT_ENOTFOUND:
790+
case GIT_EAMBIGUOUS:
789791
memset(&query->id, 0, sizeof(git_oid));
790792
query->length = 0;
791793
query->type = 0;
794+
break;
795+
796+
/* something went very wrong with the ODB; bail hard */
797+
default:
798+
return error;
792799
}
793800
}
794801

795-
if (!error)
796-
giterr_clear();
797-
798-
return error;
802+
giterr_clear();
803+
return 0;
799804
}
800805

801806
int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id)

tests/odb/mixed.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ struct expand_id_test_data expand_id_test_data[] = {
130130
{ "0ddeaded9", "0ddeaded9502971eefe1e41e34d0e536853ae20f", GIT_OBJ_BLOB },
131131
{ "f00b4e", NULL, GIT_OBJ_ANY },
132132

133+
/* this OID is too short and should be ambiguous! */
134+
{ "f00", NULL, GIT_OBJ_ANY },
135+
133136
/* some full-length object ids */
134137
{ "0000000000000000000000000000000000000000", NULL, GIT_OBJ_ANY },
135138
{
@@ -143,6 +146,12 @@ struct expand_id_test_data expand_id_test_data[] = {
143146
"4d5979b468252190cb572ae758aca36928e8a91e",
144147
GIT_OBJ_TREE
145148
},
149+
150+
/*
151+
* ensure we're not leaking the return error code for the
152+
* last lookup if the last object is invalid
153+
*/
154+
{ "0ddeadedfff", NULL, GIT_OBJ_ANY },
146155
};
147156

148157
static void setup_prefix_query(

0 commit comments

Comments
 (0)