PR 33033, Support compressed debug sections larger than 4 GiB

z_stream's avail_in and avail_out are defined as "unsigned int", so it
cannot decode an entire compressed stream in one pass if the stream is
larger than 4 GiB. The simplest solution to this problem is to use zlib's
convenient uncompress2() function, which handles the details for us.

Signed-off-by: Rui Ueyama <rui314@gmail.com>
This commit is contained in:
Rui Ueyama
2025-05-31 21:16:34 +09:00
committed by Alan Modra
parent 4187ba1fc7
commit 0921b99daf

View File

@@ -517,40 +517,23 @@ decompress_contents (bool is_zstd, bfd_byte *compressed_buffer,
#endif
}
z_stream strm;
int rc;
/* It is possible the section consists of several compressed
buffers concatenated together, so we uncompress in a loop. */
/* PR 18313: The state field in the z_stream structure is supposed
to be invisible to the user (ie us), but some compilers will
still complain about it being used without initialisation. So
we first zero the entire z_stream structure and then set the fields
that we need. */
memset (& strm, 0, sizeof strm);
strm.avail_in = compressed_size;
strm.next_in = (Bytef*) compressed_buffer;
strm.avail_out = uncompressed_size;
/* FIXME: strm.avail_in and strm.avail_out are typically unsigned
int. Supporting sizes that don't fit in an unsigned int is
possible but will require some rewriting of this function. */
if (strm.avail_in != compressed_size || strm.avail_out != uncompressed_size)
return false;
BFD_ASSERT (Z_OK == 0);
rc = inflateInit (&strm);
while (strm.avail_in > 0 && strm.avail_out > 0)
do
{
uLongf dst_len = uncompressed_size;
uLong src_len = compressed_size;
int rc = uncompress2 ((Bytef *) uncompressed_buffer, &dst_len,
(Bytef *) compressed_buffer, &src_len);
if (rc != Z_OK)
break;
strm.next_out = ((Bytef*) uncompressed_buffer
+ (uncompressed_size - strm.avail_out));
rc = inflate (&strm, Z_FINISH);
if (rc != Z_STREAM_END)
break;
rc = inflateReset (&strm);
return false;
uncompressed_buffer += dst_len;
uncompressed_size -= dst_len;
compressed_buffer += src_len;
compressed_size -= src_len;
}
return inflateEnd (&strm) == Z_OK && rc == Z_OK && strm.avail_out == 0;
while (compressed_size > 0 && uncompressed_size > 0);
return compressed_size == 0 && uncompressed_size == 0;
}
/* Compress section contents using zlib/zstd and store
@@ -987,7 +970,6 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
bfd_size_type uncompressed_size;
unsigned int uncompressed_alignment_power = 0;
enum compression_type ch_type;
z_stream strm;
compression_header_size = bfd_get_compression_header_size (abfd, sec);
if (compression_header_size > MAX_COMPRESSION_HEADER_SIZE)
@@ -1025,15 +1007,6 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
return false;
}
/* PR28530, reject sizes unsupported by decompress_contents. */
strm.avail_in = sec->size;
strm.avail_out = uncompressed_size;
if (strm.avail_in != sec->size || strm.avail_out != uncompressed_size)
{
bfd_set_error (bfd_error_nonrepresentable_section);
return false;
}
sec->compressed_size = sec->size;
sec->size = uncompressed_size;
bfd_set_section_alignment (sec, uncompressed_alignment_power);