mirror of
https://github.com/ianlancetaylor/libbacktrace.git
synced 2026-05-10 09:39:05 +08:00
libbacktrace: support multiple zstd frames
Based on patch by GitHub user ofats. * elf.c (elf_zstd_decompress_frame): New static function, broken out of elf_zstd_decompress. (elf_zstd_decompress): Call elf_zstd_decompress_frame in a loop. * zstdtest.c (test_large): Compress the file in chunks.
This commit is contained in:
57
elf.c
57
elf.c
@@ -4338,15 +4338,17 @@ elf_zstd_unpack_seq_decode (int mode,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decompress a zstd stream from PIN/SIN to POUT/SOUT. Code based on RFC 8878.
|
/* Decompress a single zstd frame from *PPIN, ending at PINEND, to *PPOUT/SOUT.
|
||||||
Return 1 on success, 0 on error. */
|
Return 1 on success, 0 on error. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
elf_zstd_decompress (const unsigned char *pin, size_t sin,
|
elf_zstd_decompress_frame (const unsigned char **ppin,
|
||||||
unsigned char *zdebug_table, unsigned char *pout,
|
const unsigned char *pinend,
|
||||||
|
unsigned char *zdebug_table, unsigned char **ppout,
|
||||||
size_t sout)
|
size_t sout)
|
||||||
{
|
{
|
||||||
const unsigned char *pinend;
|
const unsigned char *pin;
|
||||||
|
unsigned char *pout;
|
||||||
unsigned char *poutstart;
|
unsigned char *poutstart;
|
||||||
unsigned char *poutend;
|
unsigned char *poutend;
|
||||||
struct elf_zstd_seq_decode literal_decode;
|
struct elf_zstd_seq_decode literal_decode;
|
||||||
@@ -4366,9 +4368,9 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
|
|||||||
uint64_t content_size;
|
uint64_t content_size;
|
||||||
int last_block;
|
int last_block;
|
||||||
|
|
||||||
pinend = pin + sin;
|
pin = *ppin;
|
||||||
|
pout = *ppout;
|
||||||
poutstart = pout;
|
poutstart = pout;
|
||||||
poutend = pout + sout;
|
|
||||||
|
|
||||||
literal_decode.table = NULL;
|
literal_decode.table = NULL;
|
||||||
literal_decode.table_bits = -1;
|
literal_decode.table_bits = -1;
|
||||||
@@ -4394,7 +4396,7 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
|
|||||||
repeated_offset2 = 4;
|
repeated_offset2 = 4;
|
||||||
repeated_offset3 = 8;
|
repeated_offset3 = 8;
|
||||||
|
|
||||||
if (unlikely (sin < 4))
|
if (unlikely (pinend - pin < 4))
|
||||||
{
|
{
|
||||||
elf_uncompress_failed ();
|
elf_uncompress_failed ();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4492,12 +4494,14 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely (content_size != (size_t) content_size
|
if (unlikely (content_size != (size_t) content_size
|
||||||
|| (size_t) content_size != sout))
|
|| (size_t) content_size > sout))
|
||||||
{
|
{
|
||||||
elf_uncompress_failed ();
|
elf_uncompress_failed ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
poutend = pout + content_size;
|
||||||
|
|
||||||
last_block = 0;
|
last_block = 0;
|
||||||
while (!last_block)
|
while (!last_block)
|
||||||
{
|
{
|
||||||
@@ -4996,7 +5000,42 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
|
|||||||
pin += 4;
|
pin += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pin != pinend)
|
*ppin = pin;
|
||||||
|
*ppout = pout;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decompress a zstd stream from PIN/SIN to POUT/SOUT. Code based on RFC 8878.
|
||||||
|
Return 1 on success, 0 on error. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
elf_zstd_decompress (const unsigned char *pin, size_t sin,
|
||||||
|
unsigned char *zdebug_table, unsigned char *pout,
|
||||||
|
size_t sout)
|
||||||
|
{
|
||||||
|
const unsigned char *pinend;
|
||||||
|
|
||||||
|
pinend = pin + sin;
|
||||||
|
|
||||||
|
while (sin > 0)
|
||||||
|
{
|
||||||
|
const unsigned char *pin_frame;
|
||||||
|
unsigned char *pout_frame;
|
||||||
|
|
||||||
|
pin_frame = pin;
|
||||||
|
pout_frame = pout;
|
||||||
|
if (!elf_zstd_decompress_frame (&pin_frame, pinend, zdebug_table,
|
||||||
|
&pout_frame, sout))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sin -= pin_frame - pin;
|
||||||
|
pin = pin_frame;
|
||||||
|
sout -= pout_frame - pout;
|
||||||
|
pout = pout_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sout > 0)
|
||||||
{
|
{
|
||||||
elf_uncompress_failed ();
|
elf_uncompress_failed ();
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
31
zstdtest.c
31
zstdtest.c
@@ -297,8 +297,8 @@ test_large (struct backtrace_state *state ATTRIBUTE_UNUSED)
|
|||||||
size_t orig_bufsize;
|
size_t orig_bufsize;
|
||||||
size_t i;
|
size_t i;
|
||||||
char *compressed_buf;
|
char *compressed_buf;
|
||||||
size_t compressed_bufsize;
|
|
||||||
size_t compressed_size;
|
size_t compressed_size;
|
||||||
|
size_t chunk_size;
|
||||||
unsigned char *uncompressed_buf;
|
unsigned char *uncompressed_buf;
|
||||||
size_t r;
|
size_t r;
|
||||||
clockid_t cid;
|
clockid_t cid;
|
||||||
@@ -370,22 +370,39 @@ test_large (struct backtrace_state *state ATTRIBUTE_UNUSED)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
compressed_bufsize = ZSTD_compressBound (orig_bufsize);
|
/* Split the input into 100K chunks. This is to approximate the fact that lld
|
||||||
compressed_buf = malloc (compressed_bufsize);
|
splits the input into 1M shards. */
|
||||||
|
|
||||||
|
compressed_size = 0;
|
||||||
|
compressed_buf = NULL;
|
||||||
|
chunk_size = 100 << 10;
|
||||||
|
for (i = 0; i < orig_bufsize; i += chunk_size)
|
||||||
|
{
|
||||||
|
size_t chunk_input_size;
|
||||||
|
size_t chunk_compressed_size;
|
||||||
|
|
||||||
|
chunk_input_size = orig_bufsize - i;
|
||||||
|
if (chunk_input_size > chunk_size)
|
||||||
|
chunk_input_size = chunk_size;
|
||||||
|
|
||||||
|
chunk_compressed_size = ZSTD_compressBound (chunk_input_size);
|
||||||
|
compressed_buf = realloc (compressed_buf, compressed_size + chunk_compressed_size);
|
||||||
if (compressed_buf == NULL)
|
if (compressed_buf == NULL)
|
||||||
{
|
{
|
||||||
perror ("malloc");
|
perror ("realloc");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = ZSTD_compress (compressed_buf, compressed_bufsize,
|
r = ZSTD_compress (compressed_buf + compressed_size,
|
||||||
orig_buf, orig_bufsize, 3);
|
chunk_compressed_size,
|
||||||
|
orig_buf + i, chunk_input_size, 3);
|
||||||
if (ZSTD_isError (r))
|
if (ZSTD_isError (r))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "zstd compress failed: %s\n", ZSTD_getErrorName (r));
|
fprintf (stderr, "zstd compress failed: %s\n", ZSTD_getErrorName (r));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
compressed_size = r;
|
compressed_size += r;
|
||||||
|
}
|
||||||
|
|
||||||
uncompressed_buf = malloc (orig_bufsize);
|
uncompressed_buf = malloc (orig_bufsize);
|
||||||
if (uncompressed_buf == NULL)
|
if (uncompressed_buf == NULL)
|
||||||
|
|||||||
Reference in New Issue
Block a user