]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
PR 33033, Support compressed debug sections larger than 4 GiB
authorRui Ueyama <rui314@gmail.com>
Sat, 31 May 2025 12:16:34 +0000 (21:16 +0900)
committerAlan Modra <amodra@gmail.com>
Sun, 1 Jun 2025 03:50:59 +0000 (13:20 +0930)
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>
bfd/compress.c

index b63575067091344e7c25ce56e2d0deb54bbf6418..b693204a3ea12a5230141f4d288d52a74f381311 100644 (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);