Functions like parse_object_buffer(), parse_commit_buffer(), parse_tag_buffer(), and decode_tree_entry_raw() take the buffer size as an "unsigned long", while callers pass a size_t. On platforms where "long" is 32 bits, this truncates the size for objects of 4GiB or more.
When parsing large objects on those platforms, only a prefix of the buffer is parsed. For example, a signature placed at the end of a large tag can be missed.
Use size_t for the size parameter across these parsing functions. For set_commit_buffer(), the commit cache slab still stores "unsigned long" sizes due to accessors like repo_get_commit_buffer() handing out the size through an "unsigned long *" output parameter. Therefore, set_commit_buffer() narrows the size with cast_size_t_to_ulong(), dying on objects of 4GiB or more on 32-bit long platforms instead of caching a truncated size, mirroring the behavior already implemented in repo_get_commit_buffer().
parse_tree_buffer() is changed separately.
Triggering this requires processing 4GiB or more of input on a platform where "long" is 32 bits, so no test is added.
Signed-off-by: Elia Pinto <gitter.spiros@gmail.com>
---
commit.c | 8 ++++----
commit.h | 6 +++---
object-file-convert.c | 2 +-
object.c | 2 +-
object.h | 2 +-
tag.c | 2 +-
tag.h | 2 +-
7 files changed, 12 insertions(+), 12 deletions(-)
Show changes to 7 files +12 −12
commit.c, commit.h, object-file-convert.c, object.c, object.h, tag.c, tag.h
diff --git a/commit.c b/commit.c
index ad26f0b40a..a94acf4e6f 100644
--- a/commit.c
+++ b/commit.c
@@ -366,12 +366,12 @@ void free_commit_buffer_slab(struct buffer_slab *bs)
free(bs);
}
-void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer, unsigned long size)
+void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer, size_t size)
{
struct commit_buffer *v = buffer_slab_at(
r->parsed_objects->buffer_slab, commit);
v->buffer = buffer;
- v->size = size;
+ v->size = cast_size_t_to_ulong(size);
}
const void *get_cached_commit_buffer(struct repository *r, const struct commit *commit, unsigned long *sizep)
@@ -513,7 +513,7 @@ const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
return ret;
}
-int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph)
+int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, size_t size, int check_graph)
{
const char *tail = buffer;
const char *bufptr = buffer;
@@ -1195,7 +1195,7 @@ int parse_signed_commit(const struct commit *commit,
}
int parse_buffer_signed_by_header(const char *buffer,
- unsigned long size,
+ size_t size,
struct strbuf *payload,
struct strbuf *signature,
const struct git_hash_algo *algop)
diff --git a/commit.h b/commit.h
index 1061ed791b..6a6ff25e12 100644
--- a/commit.h
+++ b/commit.h
@@ -92,7 +92,7 @@ struct commit *lookup_commit_reference_by_name_gently(const char *name,
*/
struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name);
-int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph);
+int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, size_t size, int check_graph);
int repo_parse_commit_internal(struct repository *r, struct commit *item,
int quiet_on_missing, int use_commit_graph);
int repo_parse_commit_gently(struct repository *r,
@@ -131,7 +131,7 @@ void free_commit_buffer_slab(struct buffer_slab *bs);
* Associate an object buffer with the commit. The ownership of the
* memory is handed over to the commit, and must be free()-able.
*/
-void set_commit_buffer(struct repository *r, struct commit *, void *buffer, unsigned long size);
+void set_commit_buffer(struct repository *r, struct commit *, void *buffer, size_t size);
/*
* Get any cached object buffer associated with the commit. Returns NULL
@@ -381,7 +381,7 @@ int run_commit_hook(int editor_is_used, const char *index_file,
/* Parse the signature out of a header. */
int parse_buffer_signed_by_header(const char *buffer,
- unsigned long size,
+ size_t size,
struct strbuf *payload,
struct strbuf *signature,
const struct git_hash_algo *algop);
diff --git a/object-file-convert.c b/object-file-convert.c
index 63ee18630b..ead88c1021 100644
--- a/object-file-convert.c
+++ b/object-file-convert.c
@@ -51,7 +51,7 @@ int repo_oid_to_algop(struct repository *repo, const struct object_id *srcoid,
static int decode_tree_entry_raw(struct object_id *oid, const char **path,
size_t *len, const struct git_hash_algo *algo,
- const char *buf, unsigned long size)
+ const char *buf, size_t size)
{
uint16_t mode;
const unsigned hashsz = algo->rawsz;
diff --git a/object.c b/object.c
index 97f7fc0e87..541ac90dc6 100644
--- a/object.c
+++ b/object.c
@@ -258,7 +258,7 @@ enum peel_status peel_object(struct repository *r,
return peel_object_ext(r, name, oid, flags, &dummy);
}
-struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p)
+struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, size_t size, void *buffer, int *eaten_p)
{
struct object *obj;
*eaten_p = 0;
diff --git a/object.h b/object.h
index 46cade33fb..9bf23321a7 100644
--- a/object.h
+++ b/object.h
@@ -241,7 +241,7 @@ struct object *parse_object_or_die(struct repository *repo, const struct object_
* parsing it. eaten_p indicates if the object has a borrowed copy
* of buffer and the caller should not free() it.
*/
-struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p);
+struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, size_t size, void *buffer, int *eaten_p);
/*
* Allocate and return an object struct, even if you do not know the type of
diff --git a/tag.c b/tag.c
index 1a00ded6eb..414681c64f 100644
--- a/tag.c
+++ b/tag.c
@@ -127,7 +127,7 @@ void release_tag_memory(struct tag *t)
t->date = 0;
}
-int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size)
+int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, size_t size)
{
struct object_id oid;
char type[20];
diff --git a/tag.h b/tag.h
index 534687c4ca..a5f0f06c82 100644
--- a/tag.h
+++ b/tag.h
@@ -12,7 +12,7 @@ struct tag {
timestamp_t date;
};
struct tag *lookup_tag(struct repository *r, const struct object_id *oid);
-int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size);
+int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, size_t size);
int parse_tag(struct repository *r, struct tag *item);
void release_tag_memory(struct tag *t);
struct object *deref_tag(struct repository *r, struct object *, const char *, int);