make check_object() resilient to pack corruptions

The check_object() function tries to get away with the least amount of
pack access possible when it already has partial information on given
object rather than calling the more costly packed_object_info().

When things don't look right, it should just give up and fall back to
packed_object_info() directly instead of die()'ing.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Nicolas Pitre 2008-10-29 19:02:48 -04:00 committed by Junio C Hamano
parent 3d77d8774f
commit 03d660150c

View File

@ -1005,6 +1005,8 @@ static void check_object(struct object_entry *entry)
used = unpack_object_header_buffer(buf, avail, used = unpack_object_header_buffer(buf, avail,
&entry->in_pack_type, &entry->in_pack_type,
&entry->size); &entry->size);
if (used == 0)
goto give_up;
/* /*
* Determine if this is a delta and if so whether we can * Determine if this is a delta and if so whether we can
@ -1016,6 +1018,8 @@ static void check_object(struct object_entry *entry)
/* Not a delta hence we've already got all we need. */ /* Not a delta hence we've already got all we need. */
entry->type = entry->in_pack_type; entry->type = entry->in_pack_type;
entry->in_pack_header_size = used; entry->in_pack_header_size = used;
if (entry->type < OBJ_COMMIT || entry->type > OBJ_BLOB)
goto give_up;
unuse_pack(&w_curs); unuse_pack(&w_curs);
return; return;
case OBJ_REF_DELTA: case OBJ_REF_DELTA:
@ -1032,16 +1036,20 @@ static void check_object(struct object_entry *entry)
ofs = c & 127; ofs = c & 127;
while (c & 128) { while (c & 128) {
ofs += 1; ofs += 1;
if (!ofs || MSB(ofs, 7)) if (!ofs || MSB(ofs, 7)) {
die("delta base offset overflow in pack for %s", error("delta base offset overflow in pack for %s",
sha1_to_hex(entry->idx.sha1)); sha1_to_hex(entry->idx.sha1));
goto give_up;
}
c = buf[used_0++]; c = buf[used_0++];
ofs = (ofs << 7) + (c & 127); ofs = (ofs << 7) + (c & 127);
} }
ofs = entry->in_pack_offset - ofs; ofs = entry->in_pack_offset - ofs;
if (ofs <= 0 || ofs >= entry->in_pack_offset) if (ofs <= 0 || ofs >= entry->in_pack_offset) {
die("delta base offset out of bound for %s", error("delta base offset out of bound for %s",
sha1_to_hex(entry->idx.sha1)); sha1_to_hex(entry->idx.sha1));
goto give_up;
}
if (reuse_delta && !entry->preferred_base) { if (reuse_delta && !entry->preferred_base) {
struct revindex_entry *revidx; struct revindex_entry *revidx;
revidx = find_pack_revindex(p, ofs); revidx = find_pack_revindex(p, ofs);
@ -1078,6 +1086,8 @@ static void check_object(struct object_entry *entry)
*/ */
entry->size = get_size_from_delta(p, &w_curs, entry->size = get_size_from_delta(p, &w_curs,
entry->in_pack_offset + entry->in_pack_header_size); entry->in_pack_offset + entry->in_pack_header_size);
if (entry->size == 0)
goto give_up;
unuse_pack(&w_curs); unuse_pack(&w_curs);
return; return;
} }
@ -1087,6 +1097,7 @@ static void check_object(struct object_entry *entry)
* with sha1_object_info() to find about the object type * with sha1_object_info() to find about the object type
* at this point... * at this point...
*/ */
give_up:
unuse_pack(&w_curs); unuse_pack(&w_curs);
} }