https://gcc.gnu.org/g:ffe4c314b15510b97cc389bead5de8ab95cff204

commit r17-1933-gffe4c314b15510b97cc389bead5de8ab95cff204
Author: Ian Lance Taylor <[email protected]>
Date:   Sat Jun 27 08:46:14 2026 -0700

    libbacktrace: support window size in zstd decompression
    
    Reportedly this occurs on AerynOS.
    
    Patch from Ivan Molodetskikh.
    
            * elf.c (elf_zstd_decompress_frame): Support a compressed block
            that does not set the single segment flag.
            * zstdtest.c (tests): Add tests without single segment.

Diff:
---
 libbacktrace/elf.c      | 32 ++++++++++++++++++++++++--------
 libbacktrace/zstdtest.c | 31 ++++++++++++++++++++++++++++---
 2 files changed, 52 insertions(+), 11 deletions(-)

diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index f3033580e037..0de12bc112e8 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -4364,6 +4364,7 @@ elf_zstd_decompress_frame (const unsigned char **ppin,
   uint32_t repeated_offset3;
   uint16_t *scratch;
   unsigned char hdr;
+  int single_segment;
   int has_checksum;
   uint64_t content_size;
   int last_block;
@@ -4422,11 +4423,17 @@ elf_zstd_decompress_frame (const unsigned char **ppin,
 
   hdr = *pin++;
 
-  /* We expect a single frame.  */
-  if (unlikely ((hdr & (1 << 5)) == 0))
+  single_segment = (hdr & (1 << 5)) != 0;
+  if (!single_segment)
     {
-      elf_uncompress_failed ();
-      return 0;
+      if (unlikely (pin >= pinend))
+       {
+         elf_uncompress_failed ();
+         return 0;
+       }
+      /* We have all the data in memory, so we can ignore the window
+        size.  */
+      pin++;
     }
   /* Reserved bit must be zero.  */
   if (unlikely ((hdr & (1 << 3)) != 0))
@@ -4444,12 +4451,21 @@ elf_zstd_decompress_frame (const unsigned char **ppin,
   switch (hdr >> 6)
     {
     case 0:
-      if (unlikely (pin >= pinend))
+      if (!single_segment)
        {
-         elf_uncompress_failed ();
-         return 0;
+         /* The content_size is not specified, but we know it from the
+            section header.  */
+         content_size = (uint64_t) sout;
+       }
+      else
+       {
+         if (unlikely (pin >= pinend))
+           {
+             elf_uncompress_failed ();
+             return 0;
+           }
+         content_size = (uint64_t) *pin++;
        }
-      content_size = (uint64_t) *pin++;
       break;
     case 1:
       if (unlikely (pin + 1 >= pinend))
diff --git a/libbacktrace/zstdtest.c b/libbacktrace/zstdtest.c
index 7776c80fc9b3..db8072645b97 100644
--- a/libbacktrace/zstdtest.c
+++ b/libbacktrace/zstdtest.c
@@ -182,7 +182,32 @@ static const struct zstd_test tests[] =
      "\xb4\x21\x45\x3b\x10\xe4\x7b\x99\x4d\x8a\x36\x64\x5c\x77\x08\x02"
      "\xcb\xe0\xce"),
     179,
-  }
+  },
+  {
+    "window-descriptor",
+    "hello, world\n",
+    0,
+    ("\x28\xb5\x2f\xfd"
+     "\x04" /* no Single_Segment_flag; Frame_Content_Size_flag = 0 */
+     "\x00" /* Window_Descriptor */
+     "\x69\x00\x00"
+     "\x68\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x0a"
+     "\x4c\x1f\xf9\xf1"),
+    26,
+  },
+  {
+    "window-descriptor-and-content-size",
+    "hello, world\n",
+    0,
+    ("\x28\xb5\x2f\xfd"
+     "\x84" /* no Single_Segment_flag; Frame_Content_Size_flag = 2 */
+     "\x00" /* Window_Descriptor */
+     "\x0d\x00\x00\x00" /* Frame_Content_Size */
+     "\x69\x00\x00"
+     "\x68\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x0a"
+     "\x4c\x1f\xf9\xf1"),
+    30,
+  },
 };
 
 /* Test the hand coded samples.  */
@@ -217,7 +242,7 @@ test_samples (struct backtrace_state *state)
                                      error_callback_compress, NULL,
                                      uncompressed, uncompressed_len))
        {
-         fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
+         fprintf (stderr, "FAIL: test %s: uncompress failed\n", tests[i].name);
          ++failures;
        }
       else
@@ -227,7 +252,7 @@ test_samples (struct backtrace_state *state)
            {
              size_t j;
 
-             fprintf (stderr, "test %s: uncompressed data mismatch\n",
+             fprintf (stderr, "FAIL: test %s: uncompressed data mismatch\n",
                       tests[i].name);
              for (j = 0; j < uncompressed_len; ++j)
                if (tests[i].uncompressed[j] != uncompressed[j])

Reply via email to