This patch to libbacktrace corrects the zstd decompressor to handle a
compressed frame that has no sequences. This is used for a frame that
consists only of a sequence of literals. It's an uncommon case and I
don't have a reasonably sized test case. I do have a large test case
(163169518 bytes) provided as part of
https://github.com/ianlancetaylor/libbacktrace/issues/164. I've
verified that without this patch that test case fails to decompress,
and with this patch the output is the same as the output from zunstd.
Bootstrapped and ran libbacktrace testsuite on x86_64-pc-linux-gnu.
Committed to mainline.
Ian
* elf.c (elf_zstd_decompress_frame): Support a compressed block
with no sequences, only literals.
fbf5aa934d4170c2cdde324830f23571d26f1757
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 5aee4afd0d1..f3033580e03 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -4620,6 +4620,11 @@ elf_zstd_decompress_frame (const unsigned char **ppin,
pin += 2;
}
+ pback = NULL;
+ bits = 0;
+ literal_state = 0;
+ offset_state = 0;
+ match_state = 0;
if (seq_count > 0)
{
int (*pfn)(const struct elf_zstd_fse_entry *,
@@ -4659,27 +4664,27 @@ elf_zstd_decompress_frame (const unsigned char **ppin,
match_fse_table, 9, pfn,
&match_decode))
return 0;
- }
- pback = pblockend - 1;
- if (!elf_fetch_backward_init (&pback, pin, &val, &bits))
- return 0;
+ pback = pblockend - 1;
+ if (!elf_fetch_backward_init (&pback, pin, &val, &bits))
+ return 0;
- bits -= literal_decode.table_bits;
- literal_state = ((val >> bits)
- & ((1U << literal_decode.table_bits) - 1));
+ bits -= literal_decode.table_bits;
+ literal_state = ((val >> bits)
+ & ((1U << literal_decode.table_bits) - 1));
- if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))
- return 0;
- bits -= offset_decode.table_bits;
- offset_state = ((val >> bits)
- & ((1U << offset_decode.table_bits) - 1));
+ if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))
+ return 0;
+ bits -= offset_decode.table_bits;
+ offset_state = ((val >> bits)
+ & ((1U << offset_decode.table_bits) - 1));
- if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))
- return 0;
- bits -= match_decode.table_bits;
- match_state = ((val >> bits)
- & ((1U << match_decode.table_bits) - 1));
+ if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))
+ return 0;
+ bits -= match_decode.table_bits;
+ match_state = ((val >> bits)
+ & ((1U << match_decode.table_bits) - 1));
+ }
seq = 0;
while (1)
@@ -4701,6 +4706,40 @@ elf_zstd_decompress_frame (const unsigned char **ppin,
uint32_t need;
uint32_t add;
+ if (unlikely (seq >= seq_count))
+ {
+ /* Copy remaining literals. */
+ if (literal_count > 0 && plit != pout)
+ {
+ if (unlikely ((size_t)(poutend - pout)
+ < literal_count))
+ {
+ elf_uncompress_failed ();
+ return 0;
+ }
+
+ if ((size_t)(plit - pout) < literal_count)
+ {
+ uint32_t move;
+
+ move = plit - pout;
+ while (literal_count > move)
+ {
+ memcpy (pout, plit, move);
+ pout += move;
+ plit += move;
+ literal_count -= move;
+ }
+ }
+
+ memcpy (pout, plit, literal_count);
+ }
+
+ pout += literal_count;
+
+ break;
+ }
+
pt = &offset_decode.table[offset_state];
offset_basebits = pt->basebits;
offset_baseline = pt->baseline;
@@ -4938,40 +4977,6 @@ elf_zstd_decompress_frame (const unsigned char **ppin,
}
}
}
-
- if (unlikely (seq >= seq_count))
- {
- /* Copy remaining literals. */
- if (literal_count > 0 && plit != pout)
- {
- if (unlikely ((size_t)(poutend - pout)
- < literal_count))
- {
- elf_uncompress_failed ();
- return 0;
- }
-
- if ((size_t)(plit - pout) < literal_count)
- {
- uint32_t move;
-
- move = plit - pout;
- while (literal_count > move)
- {
- memcpy (pout, plit, move);
- pout += move;
- plit += move;
- literal_count -= move;
- }
- }
-
- memcpy (pout, plit, literal_count);
- }
-
- pout += literal_count;
-
- break;
- }
}
pin = pblockend;