From 21ccbd2e2f855a18657bc38c7e8af88b3ec9eb0c Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 17 Apr 2020 21:10:23 -0700 Subject: [PATCH] Generalize test_zlib to test_trailing_bytes Do the same test for DEFLATE and gzip. --- Makefile | 2 +- programs/test_trailing_bytes.c | 154 +++++++++++++++++++++++++++++++++ programs/test_zlib.c | 106 ----------------------- 3 files changed, 155 insertions(+), 107 deletions(-) create mode 100644 programs/test_trailing_bytes.c delete mode 100644 programs/test_zlib.c diff --git a/Makefile b/Makefile index f6d9f17..1ce57e6 100644 --- a/Makefile +++ b/Makefile @@ -217,7 +217,7 @@ TEST_PROG_SRC := programs/benchmark.c \ programs/test_checksums.c \ programs/test_incomplete_codes.c \ programs/test_slow_decompression.c \ - programs/test_zlib.c + programs/test_trailing_bytes.c NONTEST_PROGRAMS := $(NONTEST_PROG_SRC:programs/%.c=%$(PROG_SUFFIX)) DEFAULT_TARGETS += $(NONTEST_PROGRAMS) diff --git a/programs/test_trailing_bytes.c b/programs/test_trailing_bytes.c new file mode 100644 index 0000000..ca23378 --- /dev/null +++ b/programs/test_trailing_bytes.c @@ -0,0 +1,154 @@ +/* + * test_trailing_bytes.c + * + * Test that decompression correctly stops at the end of the first DEFLATE, + * zlib, or gzip stream, and doesn't process any additional trailing bytes. + */ + +#include "test_util.h" + +static const struct { + size_t (LIBDEFLATEAPI *compress)( + struct libdeflate_compressor *compressor, + const void *in, size_t in_nbytes, + void *out, size_t out_nbytes_avail); + enum libdeflate_result (LIBDEFLATEAPI *decompress)( + struct libdeflate_decompressor *decompressor, + const void *in, size_t in_nbytes, + void *out, size_t out_nbytes_avail, + size_t *actual_out_nbytes_ret); + enum libdeflate_result (LIBDEFLATEAPI *decompress_ex)( + struct libdeflate_decompressor *decompressor, + const void *in, size_t in_nbytes, + void *out, size_t out_nbytes_avail, + size_t *actual_in_nbytes_ret, + size_t *actual_out_nbytes_ret); +} codecs[] = { + { + .compress = libdeflate_deflate_compress, + .decompress = libdeflate_deflate_decompress, + .decompress_ex = libdeflate_deflate_decompress_ex, + }, { + .compress = libdeflate_zlib_compress, + .decompress = libdeflate_zlib_decompress, + .decompress_ex = libdeflate_zlib_decompress_ex, + }, { + .compress = libdeflate_gzip_compress, + .decompress = libdeflate_gzip_decompress, + .decompress_ex = libdeflate_gzip_decompress_ex, + } +}; + +int +tmain(int argc, tchar *argv[]) +{ + const size_t original_nbytes = 32768; + const size_t compressed_nbytes_total = 32768; + /* + * Don't use the full buffer for compressed data, because we want to + * test whether decompression can deal with additional trailing bytes. + * + * Note: we can't use a guarded buffer (i.e. a buffer where the byte + * after compressed_nbytes is unmapped) because the decompressor may + * read a few bytes beyond the end of the stream (but ultimately not + * actually use those bytes) as long as they are within the buffer. + */ + const size_t compressed_nbytes_avail = 30000; + size_t i; + u8 *original; + u8 *compressed; + u8 *decompressed; + struct libdeflate_compressor *c; + struct libdeflate_decompressor *d; + size_t compressed_nbytes; + enum libdeflate_result res; + size_t actual_compressed_nbytes; + size_t actual_decompressed_nbytes; + + program_invocation_name = get_filename(argv[0]); + + ASSERT(compressed_nbytes_avail < compressed_nbytes_total); + + /* Prepare some dummy data to compress */ + original = xmalloc(original_nbytes); + ASSERT(original != NULL); + for (i = 0; i < original_nbytes; i++) + original[i] = (i % 123) + (i % 1023); + + compressed = xmalloc(compressed_nbytes_total); + ASSERT(compressed != NULL); + memset(compressed, 0, compressed_nbytes_total); + + decompressed = xmalloc(original_nbytes); + ASSERT(decompressed != NULL); + + c = libdeflate_alloc_compressor(6); + ASSERT(c != NULL); + + d = libdeflate_alloc_decompressor(); + ASSERT(d != NULL); + + for (i = 0; i < ARRAY_LEN(codecs); i++) { + compressed_nbytes = codecs[i].compress(c, original, + original_nbytes, + compressed, + compressed_nbytes_avail); + ASSERT(compressed_nbytes > 0); + ASSERT(compressed_nbytes <= compressed_nbytes_avail); + + /* Test decompress() of stream that fills the whole buffer */ + actual_decompressed_nbytes = 0; + memset(decompressed, 0, original_nbytes); + res = codecs[i].decompress(d, compressed, compressed_nbytes, + decompressed, original_nbytes, + &actual_decompressed_nbytes); + ASSERT(res == LIBDEFLATE_SUCCESS); + ASSERT(actual_decompressed_nbytes == original_nbytes); + ASSERT(memcmp(decompressed, original, original_nbytes) == 0); + + /* Test decompress_ex() of stream that fills the whole buffer */ + actual_compressed_nbytes = actual_decompressed_nbytes = 0; + memset(decompressed, 0, original_nbytes); + res = codecs[i].decompress_ex(d, compressed, compressed_nbytes, + decompressed, original_nbytes, + &actual_compressed_nbytes, + &actual_decompressed_nbytes); + ASSERT(res == LIBDEFLATE_SUCCESS); + ASSERT(actual_compressed_nbytes == compressed_nbytes); + ASSERT(actual_decompressed_nbytes == original_nbytes); + ASSERT(memcmp(decompressed, original, original_nbytes) == 0); + + /* Test decompress() of stream with trailing bytes */ + actual_decompressed_nbytes = 0; + memset(decompressed, 0, original_nbytes); + res = codecs[i].decompress(d, compressed, + compressed_nbytes_total, + decompressed, original_nbytes, + &actual_decompressed_nbytes); + ASSERT(res == LIBDEFLATE_SUCCESS); + ASSERT(actual_decompressed_nbytes == original_nbytes); + ASSERT(memcmp(decompressed, original, original_nbytes) == 0); + + /* Test decompress_ex() of stream with trailing bytes */ + actual_compressed_nbytes = actual_decompressed_nbytes = 0; + memset(decompressed, 0, original_nbytes); + res = codecs[i].decompress_ex(d, compressed, + compressed_nbytes_total, + decompressed, original_nbytes, + &actual_compressed_nbytes, + &actual_decompressed_nbytes); + ASSERT(res == LIBDEFLATE_SUCCESS); + ASSERT(actual_compressed_nbytes == compressed_nbytes); + ASSERT(actual_decompressed_nbytes == original_nbytes); + ASSERT(memcmp(decompressed, original, original_nbytes) == 0); + } + + printf("Trailing bytes decompression tests passed!\n"); + + free(original); + free(compressed); + free(decompressed); + libdeflate_free_compressor(c); + libdeflate_free_decompressor(d); + return 0; +} diff --git a/programs/test_zlib.c b/programs/test_zlib.c deleted file mode 100644 index 706d4bb..0000000 --- a/programs/test_zlib.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * test_zlib.c - * - * Verify that libdeflate_zlib_decompress and libdeflate_zlib_decompress_ex can - * correctly decompress the results of libdeflate_zlib_compress. Also checks - * whether decompression correctly handles additional trailing bytes in the - * compressed buffer. - */ - -#include - -#include "test_util.h" - -static void -test_decompress(u8 const* compressed, size_t compressed_nbytes, - u8 const* expected, size_t expected_nbytes) -{ - struct libdeflate_decompressor* d = libdeflate_alloc_decompressor(); - ASSERT(d != NULL); - - size_t decompressed_nbytes = expected_nbytes; - u8 *decompressed = xmalloc(decompressed_nbytes); - - size_t actual_decompressed_nbytes = 0; - enum libdeflate_result res = - libdeflate_zlib_decompress(d, compressed, compressed_nbytes, - decompressed, decompressed_nbytes, - &actual_decompressed_nbytes); - ASSERT(res == LIBDEFLATE_SUCCESS); - ASSERT(actual_decompressed_nbytes == expected_nbytes); - ASSERT(memcmp(expected, decompressed, expected_nbytes) == 0); - - free(decompressed); - libdeflate_free_decompressor(d); -} - -static void -test_decompress_ex(u8 const* compressed, size_t compressed_nbytes, - size_t expected_actual_compressed_nbytes, - u8 const* expected, size_t expected_nbytes) -{ - struct libdeflate_decompressor* d = libdeflate_alloc_decompressor(); - ASSERT(d != NULL); - - size_t decompressed_nbytes = expected_nbytes; - u8 *decompressed = xmalloc(decompressed_nbytes); - - size_t actual_compressed_nbytes = 0; - size_t actual_decompressed_nbytes = 0; - enum libdeflate_result res = - libdeflate_zlib_decompress_ex(d, compressed, compressed_nbytes, - decompressed, decompressed_nbytes, - &actual_compressed_nbytes, - &actual_decompressed_nbytes); - ASSERT(res == LIBDEFLATE_SUCCESS); - ASSERT(actual_compressed_nbytes == expected_actual_compressed_nbytes); - ASSERT(actual_decompressed_nbytes == expected_nbytes); - ASSERT(memcmp(expected, decompressed, expected_nbytes) == 0); - - free(decompressed); - libdeflate_free_decompressor(d); -} - -int -tmain(int argc, tchar *argv[]) -{ - program_invocation_name = get_filename(argv[0]); - - size_t original_nbytes = 32768; - u8 *original = xmalloc(original_nbytes); - - /* Prepare some dummy data to compress */ - for (size_t i = 0; i < original_nbytes; ++i) { - original[i] = (i % 123) + (i % 1023); - } - - size_t compressed_nbytes_total = 32768; - u8 *compressed = xmalloc(compressed_nbytes_total); - memset(compressed, 0x00, compressed_nbytes_total); - - /* - * Don't use the full buffer for compressed data, because we want to - * test whether decompression can deal with additional trailing bytes. - */ - size_t compressed_nbytes_avail = 30000; - ASSERT(compressed_nbytes_avail < compressed_nbytes_total); - - struct libdeflate_compressor* c = libdeflate_alloc_compressor(6); - ASSERT(c != NULL); - size_t compressed_nbytes = - libdeflate_zlib_compress(c, original, original_nbytes, - compressed, compressed_nbytes_avail); - ASSERT(compressed_nbytes > 0); - libdeflate_free_compressor(c); - - test_decompress(compressed, compressed_nbytes, original, original_nbytes); - test_decompress(compressed, compressed_nbytes_total, original, original_nbytes); - test_decompress_ex(compressed, compressed_nbytes_total, compressed_nbytes, - original, original_nbytes); - - printf("libdeflate_zlib_* tests passed!\n"); - - free(compressed); - free(original); - return 0; -}