odb: guard against data loss checking out a huge file

This introduces an additional guard for platforms where `unsigned long` and `size_t` are not of the same size. If the size of an object in the database would overflow `unsigned long`, instead we now exit with an error. A complete fix will have to update _many_ other functions throughout the codebase to use `size_t` instead of `unsigned long`. It will have to be implemented at some stage. This commit puts in a stop-gap for the time being. Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Matt Cooper <vtbassmatt@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Matt Cooper committed Nov 2, 2021 at 15:46 UTC d6a09e795d77ddc76c5141047340dc3cb62355f4
3 files changed +9 -9
delta.h
+3 -3
@@ -90,15 +90,15 @@ static inline unsigned long get_delta_hdr_size(const unsigned char **datap,
90 const unsigned char *top)
91 {
92 const unsigned char *data = *datap;
93 - unsigned long cmd, size = 0;
93 + size_t cmd, size = 0;
94 int i = 0;
95 do {
96 cmd = *data++;
97 - size |= (cmd & 0x7f) << i;
97 + size |= st_left_shift(cmd & 0x7f, i);
98 i += 7;
99 } while (cmd & 0x80 && data < top);
100 *datap = data;
101 - return size;
101 + return cast_size_t_to_ulong(size);
102 }
103
104 #endif
object-file.c
+3 -3
@@ -1344,7 +1344,7 @@ static int parse_loose_header_extended(const char *hdr, struct object_info *oi,
1344 unsigned int flags)
1345 {
1346 const char *type_buf = hdr;
1347 - unsigned long size;
1347 + size_t size;
1348 int type, type_len = 0;
1349
1350 /*
@@ -1388,12 +1388,12 @@ static int parse_loose_header_extended(const char *hdr, struct object_info *oi,
1388 if (c > 9)
1389 break;
1390 hdr++;
1391 - size = size * 10 + c;
1391 + size = st_add(st_mult(size, 10), c);
1392 }
1393 }
1394
1395 if (oi->sizep)
1396 - *oi->sizep = size;
1396 + *oi->sizep = cast_size_t_to_ulong(size);
1397
1398 /*
1399 * The length must be followed by a zero byte
packfile.c
+3 -3
@@ -1059,7 +1059,7 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
1059 unsigned long len, enum object_type *type, unsigned long *sizep)
1060 {
1061 unsigned shift;
1062 - unsigned long size, c;
1062 + size_t size, c;
1063 unsigned long used = 0;
1064
1065 c = buf[used++];
@@ -1073,10 +1073,10 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
1073 break;
1074 }
1075 c = buf[used++];
1076 - size += (c & 0x7f) << shift;
1076 + size = st_add(size, st_left_shift(c & 0x7f, shift));
1077 shift += 7;
1078 }
1079 - *sizep = size;
1079 + *sizep = cast_size_t_to_ulong(size);
1080 return used;
1081 }
1082