зеркало из https://github.com/microsoft/git.git
Merge branch 'nd/pack-ofs-4gb-limit' into maint
"git pack-objects" and "git index-pack" mostly operate with off_t when talking about the offset of objects in a packfile, but there were a handful of places that used "unsigned long" to hold that value, leading to an unintended truncation. * nd/pack-ofs-4gb-limit: fsck: use streaming interface for large blobs in pack pack-objects: do not truncate result in-pack object size on 32-bit systems index-pack: correct "offset" type in unpack_entry_data() index-pack: report correct bad object offsets even if they are large index-pack: correct "len" type in unpack_data() sha1_file.c: use type off_t* for object_info->disk_sizep pack-objects: pass length to check_pack_crc() without truncation
This commit is contained in:
Коммит
aa9136a87e
|
@ -131,7 +131,7 @@ struct expand_data {
|
|||
unsigned char sha1[20];
|
||||
enum object_type type;
|
||||
unsigned long size;
|
||||
unsigned long disk_size;
|
||||
off_t disk_size;
|
||||
const char *rest;
|
||||
unsigned char delta_base_sha1[20];
|
||||
|
||||
|
@ -191,7 +191,7 @@ static void expand_atom(struct strbuf *sb, const char *atom, int len,
|
|||
if (data->mark_query)
|
||||
data->info.disk_sizep = &data->disk_size;
|
||||
else
|
||||
strbuf_addf(sb, "%lu", data->disk_size);
|
||||
strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)data->disk_size);
|
||||
} else if (is_atom("rest", atom, len)) {
|
||||
if (data->mark_query)
|
||||
data->split_on_whitespace = 1;
|
||||
|
|
|
@ -356,6 +356,10 @@ static int fsck_sha1(const unsigned char *sha1)
|
|||
static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
|
||||
unsigned long size, void *buffer, int *eaten)
|
||||
{
|
||||
/*
|
||||
* Note, buffer may be NULL if type is OBJ_BLOB. See
|
||||
* verify_packfile(), data_valid variable for details.
|
||||
*/
|
||||
struct object *obj;
|
||||
obj = parse_object_buffer(sha1, type, size, buffer, eaten);
|
||||
if (!obj) {
|
||||
|
|
|
@ -338,10 +338,10 @@ static void parse_pack_header(void)
|
|||
use(sizeof(struct pack_header));
|
||||
}
|
||||
|
||||
static NORETURN void bad_object(unsigned long offset, const char *format,
|
||||
static NORETURN void bad_object(off_t offset, const char *format,
|
||||
...) __attribute__((format (printf, 2, 3)));
|
||||
|
||||
static NORETURN void bad_object(unsigned long offset, const char *format, ...)
|
||||
static NORETURN void bad_object(off_t offset, const char *format, ...)
|
||||
{
|
||||
va_list params;
|
||||
char buf[1024];
|
||||
|
@ -349,7 +349,8 @@ static NORETURN void bad_object(unsigned long offset, const char *format, ...)
|
|||
va_start(params, format);
|
||||
vsnprintf(buf, sizeof(buf), format, params);
|
||||
va_end(params);
|
||||
die(_("pack has bad object at offset %lu: %s"), offset, buf);
|
||||
die(_("pack has bad object at offset %"PRIuMAX": %s"),
|
||||
(uintmax_t)offset, buf);
|
||||
}
|
||||
|
||||
static inline struct thread_local *get_thread_data(void)
|
||||
|
@ -429,7 +430,7 @@ static int is_delta_type(enum object_type type)
|
|||
return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
|
||||
}
|
||||
|
||||
static void *unpack_entry_data(unsigned long offset, unsigned long size,
|
||||
static void *unpack_entry_data(off_t offset, unsigned long size,
|
||||
enum object_type type, unsigned char *sha1)
|
||||
{
|
||||
static char fixed_buf[8192];
|
||||
|
@ -549,13 +550,13 @@ static void *unpack_data(struct object_entry *obj,
|
|||
void *cb_data)
|
||||
{
|
||||
off_t from = obj[0].idx.offset + obj[0].hdr_size;
|
||||
unsigned long len = obj[1].idx.offset - from;
|
||||
off_t len = obj[1].idx.offset - from;
|
||||
unsigned char *data, *inbuf;
|
||||
git_zstream stream;
|
||||
int status;
|
||||
|
||||
data = xmallocz(consume ? 64*1024 : obj->size);
|
||||
inbuf = xmalloc((len < 64*1024) ? len : 64*1024);
|
||||
inbuf = xmalloc((len < 64*1024) ? (int)len : 64*1024);
|
||||
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
git_inflate_init(&stream);
|
||||
|
@ -563,15 +564,15 @@ static void *unpack_data(struct object_entry *obj,
|
|||
stream.avail_out = consume ? 64*1024 : obj->size;
|
||||
|
||||
do {
|
||||
ssize_t n = (len < 64*1024) ? len : 64*1024;
|
||||
ssize_t n = (len < 64*1024) ? (ssize_t)len : 64*1024;
|
||||
n = xpread(get_thread_data()->pack_fd, inbuf, n, from);
|
||||
if (n < 0)
|
||||
die_errno(_("cannot pread pack file"));
|
||||
if (!n)
|
||||
die(Q_("premature end of pack file, %lu byte missing",
|
||||
"premature end of pack file, %lu bytes missing",
|
||||
len),
|
||||
len);
|
||||
die(Q_("premature end of pack file, %"PRIuMAX" byte missing",
|
||||
"premature end of pack file, %"PRIuMAX" bytes missing",
|
||||
(unsigned int)len),
|
||||
(uintmax_t)len);
|
||||
from += n;
|
||||
len -= n;
|
||||
stream.next_in = inbuf;
|
||||
|
|
|
@ -341,15 +341,15 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent
|
|||
}
|
||||
|
||||
/* Return 0 if we will bust the pack-size limit */
|
||||
static unsigned long write_reuse_object(struct sha1file *f, struct object_entry *entry,
|
||||
unsigned long limit, int usable_delta)
|
||||
static off_t write_reuse_object(struct sha1file *f, struct object_entry *entry,
|
||||
unsigned long limit, int usable_delta)
|
||||
{
|
||||
struct packed_git *p = entry->in_pack;
|
||||
struct pack_window *w_curs = NULL;
|
||||
struct revindex_entry *revidx;
|
||||
off_t offset;
|
||||
enum object_type type = entry->type;
|
||||
unsigned long datalen;
|
||||
off_t datalen;
|
||||
unsigned char header[10], dheader[10];
|
||||
unsigned hdrlen;
|
||||
|
||||
|
@ -415,11 +415,12 @@ static unsigned long write_reuse_object(struct sha1file *f, struct object_entry
|
|||
}
|
||||
|
||||
/* Return 0 if we will bust the pack-size limit */
|
||||
static unsigned long write_object(struct sha1file *f,
|
||||
struct object_entry *entry,
|
||||
off_t write_offset)
|
||||
static off_t write_object(struct sha1file *f,
|
||||
struct object_entry *entry,
|
||||
off_t write_offset)
|
||||
{
|
||||
unsigned long limit, len;
|
||||
unsigned long limit;
|
||||
off_t len;
|
||||
int usable_delta, to_reuse;
|
||||
|
||||
if (!pack_to_stdout)
|
||||
|
@ -491,7 +492,7 @@ static enum write_one_status write_one(struct sha1file *f,
|
|||
struct object_entry *e,
|
||||
off_t *offset)
|
||||
{
|
||||
unsigned long size;
|
||||
off_t size;
|
||||
int recursing;
|
||||
|
||||
/*
|
||||
|
|
2
cache.h
2
cache.h
|
@ -1508,7 +1508,7 @@ struct object_info {
|
|||
/* Request */
|
||||
enum object_type *typep;
|
||||
unsigned long *sizep;
|
||||
unsigned long *disk_sizep;
|
||||
off_t *disk_sizep;
|
||||
unsigned char *delta_base_sha1;
|
||||
struct strbuf *typename;
|
||||
|
||||
|
|
23
pack-check.c
23
pack-check.c
|
@ -105,6 +105,8 @@ static int verify_packfile(struct packed_git *p,
|
|||
void *data;
|
||||
enum object_type type;
|
||||
unsigned long size;
|
||||
off_t curpos;
|
||||
int data_valid;
|
||||
|
||||
if (p->index_version > 1) {
|
||||
off_t offset = entries[i].offset;
|
||||
|
@ -116,8 +118,25 @@ static int verify_packfile(struct packed_git *p,
|
|||
sha1_to_hex(entries[i].sha1),
|
||||
p->pack_name, (uintmax_t)offset);
|
||||
}
|
||||
data = unpack_entry(p, entries[i].offset, &type, &size);
|
||||
if (!data)
|
||||
|
||||
curpos = entries[i].offset;
|
||||
type = unpack_object_header(p, w_curs, &curpos, &size);
|
||||
unuse_pack(w_curs);
|
||||
|
||||
if (type == OBJ_BLOB && big_file_threshold <= size) {
|
||||
/*
|
||||
* Let check_sha1_signature() check it with
|
||||
* the streaming interface; no point slurping
|
||||
* the data in-core only to discard.
|
||||
*/
|
||||
data = NULL;
|
||||
data_valid = 0;
|
||||
} else {
|
||||
data = unpack_entry(p, entries[i].offset, &type, &size);
|
||||
data_valid = 1;
|
||||
}
|
||||
|
||||
if (data_valid && !data)
|
||||
err = error("cannot unpack %s from %s at offset %"PRIuMAX"",
|
||||
sha1_to_hex(entries[i].sha1), p->pack_name,
|
||||
(uintmax_t)entries[i].offset);
|
||||
|
|
1
pack.h
1
pack.h
|
@ -74,6 +74,7 @@ struct pack_idx_entry {
|
|||
|
||||
|
||||
struct progress;
|
||||
/* Note, the data argument could be NULL if object type is blob */
|
||||
typedef int (*verify_fn)(const unsigned char*, enum object_type, unsigned long, void*, int*);
|
||||
|
||||
extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, const struct pack_idx_option *, const unsigned char *sha1);
|
||||
|
|
|
@ -2281,7 +2281,7 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
|
|||
|
||||
if (do_check_packed_object_crc && p->index_version > 1) {
|
||||
struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
|
||||
unsigned long len = revidx[1].offset - obj_offset;
|
||||
off_t len = revidx[1].offset - obj_offset;
|
||||
if (check_pack_crc(p, &w_curs, obj_offset, len, revidx->nr)) {
|
||||
const unsigned char *sha1 =
|
||||
nth_packed_object_sha1(p, revidx->nr);
|
||||
|
|
|
@ -177,10 +177,9 @@ test_expect_success 'zip achiving, deflate' '
|
|||
git archive --format=zip HEAD >/dev/null
|
||||
'
|
||||
|
||||
test_expect_success 'fsck' '
|
||||
test_must_fail git fsck 2>err &&
|
||||
n=$(grep "error: attempting to allocate .* over limit" err | wc -l) &&
|
||||
test "$n" -gt 1
|
||||
test_expect_success 'fsck large blobs' '
|
||||
git fsck 2>err &&
|
||||
test_must_be_empty err
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
Загрузка…
Ссылка в новой задаче