Skip to content

Commit 2d47afd

Browse files
committed
zlib: properly clamp to uLong
On platforms where `unsigned long` and `size_t` differ in bit size, we want to clamp the buffers we pass to zlib to the former's size, as per d05d666 (git-zlib: handle data streams larger than 4GB, 2026-05-08). The logic introduced in that commit performs a clamping to the bits, though, which fails to do what is needed here: If too many bytes are available in the buffers, we need to clamp to the maximum value of an `unsigned long`. Otherwise, we ask zlib to use too small buffers, in the worst case using 0 as the size (think: a value whose 32 lowest bits are all zero). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 7a094d6 commit 2d47afd

1 file changed

Lines changed: 9 additions & 4 deletions

File tree

git-zlib.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,17 @@ static inline uInt zlib_buf_cap(unsigned long len)
3838
return (ZLIB_BUF_MAX < len) ? ZLIB_BUF_MAX : len;
3939
}
4040

41+
static inline uLong zlib_uLong_cap(size_t s)
42+
{
43+
return s < ULONG_MAX_VALUE ? (uLong)s : ULONG_MAX_VALUE;
44+
}
45+
4146
static void zlib_pre_call(git_zstream *s)
4247
{
4348
s->z.next_in = s->next_in;
4449
s->z.next_out = s->next_out;
45-
s->z.total_in = (uLong)(s->total_in & ULONG_MAX_VALUE);
46-
s->z.total_out = (uLong)(s->total_out & ULONG_MAX_VALUE);
50+
s->z.total_in = zlib_uLong_cap(s->total_in);
51+
s->z.total_out = zlib_uLong_cap(s->total_out);
4752
s->z.avail_in = zlib_buf_cap(s->avail_in);
4853
s->z.avail_out = zlib_buf_cap(s->avail_out);
4954
}
@@ -60,15 +65,15 @@ static void zlib_post_call(git_zstream *s, int status)
6065
* We track our own totals and verify only the low bits match.
6166
*/
6267
if ((s->z.total_out & ULONG_MAX_VALUE) !=
63-
((s->total_out + bytes_produced) & ULONG_MAX_VALUE))
68+
((zlib_uLong_cap(s->total_out) + bytes_produced) & ULONG_MAX_VALUE))
6469
BUG("total_out mismatch");
6570
/*
6671
* zlib does not update total_in when it returns Z_NEED_DICT,
6772
* causing a mismatch here. Skip the sanity check in that case.
6873
*/
6974
if (status != Z_NEED_DICT &&
7075
(s->z.total_in & ULONG_MAX_VALUE) !=
71-
((s->total_in + bytes_consumed) & ULONG_MAX_VALUE))
76+
((zlib_uLong_cap(s->total_in) + bytes_consumed) & ULONG_MAX_VALUE))
7277
BUG("total_in mismatch");
7378

7479
s->total_out += bytes_produced;

0 commit comments

Comments
 (0)