From: Nathan Moinvaziri Date: Sat, 26 Oct 2019 20:03:25 +0000 (-0700) Subject: Added regression test for deflateEnd returning -3 when using deflate quick. #382 X-Git-Tag: 1.9.9-b1~212 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b6136c629c3395be5449c0b2526dceb443b260fc;p=thirdparty%2Fzlib-ng.git Added regression test for deflateEnd returning -3 when using deflate quick. #382 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index a54dda5d5..c4b056b03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1029,6 +1029,10 @@ if(ZLIB_ENABLE_TESTS) endif() endif() + add_executable(minideflate test/minideflate.c) + configure_test_executable(minideflate) + target_link_libraries(minideflate zlib) + add_executable(switchlevels test/switchlevels.c) configure_test_executable(switchlevels) target_link_libraries(switchlevels zlib) @@ -1220,6 +1224,27 @@ if(ZLIB_ENABLE_TESTS) -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/test/GH-364/test.bin -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake) + set(GH_382_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ -c -m 1 -w -15 -1 -s 4) + add_test(NAME GH-382-deflate COMMAND + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${GH_382_COMMAND}" + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/test/GH-382/defneg3.dat + -DOUTPUT=${CMAKE_CURRENT_SOURCE_DIR}/test/GH-382/defneg3.dat.zz + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake) + + set(GH_382_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ -c -d -m 1 -w -15) + add_test(NAME GH-382-inflate COMMAND + COMMAND ${CMAKE_COMMAND} + "-DCOMMAND=${GH_382_COMMAND}" + -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/test/GH-382/defneg3.dat.zz + -DOUTPUT=${CMAKE_CURRENT_SOURCE_DIR}/test/GH-382/defneg3.dat.out + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake) + + add_test(NAME GH-382-cmp + COMMAND ${CMAKE_COMMAND} -E compare_files + ${CMAKE_CURRENT_SOURCE_DIR}/test/GH-382/defneg3.dat + ${CMAKE_CURRENT_SOURCE_DIR}/test/GH-382/defneg3.dat.out) + set(GH_536_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $ 6 9744 1 91207) add_test(NAME GH-536-segfault COMMAND ${CMAKE_COMMAND} diff --git a/test/GH-382/defneg3.dat b/test/GH-382/defneg3.dat new file mode 100644 index 000000000..5fa6a0804 --- /dev/null +++ b/test/GH-382/defneg3.dat @@ -0,0 +1 @@ +o̙Ì?ÌOÌÃÌḩÌÕÌ>ÌÌÌà̝̹̘ÌÔÌEÌs̗̍Ì4̢̙̑Ì6ÌÌØÌæÌ\ÌÌÌ5̪̲̕ÌmÌ̖Ìç̺̜ÌÙ̧ÌÌíÌí̖ÌÌëÌmÌìÌÎ̵ÌGÌïÌOÌÛÌ ÌÃÌòÌÎÌô̄Ì;̔Ìý̒ÌÓÌÀÌ×Ì,ÌÑÌ¢ÌáÌAÌ9Ì»ÌæÌ‚ÌÂÌsÌý̼ÌÝÌÌ­ÌeÌòÌÝÌUÌuÌí̱ÌËÌwÌù̕ÌDÌß̋̽Ìt̞̣̹ÌöÌôÌOÌîÌí̅ÌpÌGÌḭ̀ÌÀÌ(ÌÌÌ̤Ì{̓ÌßÌïÌÕÌÌøÌÌMÌ#̝Ìí̵ÌdÌ·ÌIÌßÌhÌ_ÌpÌJÌÇÌ¢ÌÎÌÌóÌêÌÁÌ;Ì<̘ÌZÌÈÌÑÌoÌW̄̿Ì}ÌáÌÌÌ:Ìá̧̻̕ÌeÌFÌtÌ(ÌEÌoÌàÌpÌÌ¢Ì(Ì;ÌþÌëÌóÌ!̹̹ÌÉÌ̜ÌîÌÖÌ4ÌÈÌ3Ìë̋ÌBÌŽÌÆÌuÌPÌ6̓ÌþÌ&̦̳̕ÌÁÌðÌ»ÌÌÌTÌÀ̧ÌbÌÌÒÌÕÌëÌ{ÌÆÌ¡ÌÊÌNÌ9ÌÇÌÌBÌÑ \ No newline at end of file diff --git a/test/README.md b/test/README.md index 095f4dc7d..247d5bac7 100644 --- a/test/README.md +++ b/test/README.md @@ -10,24 +10,27 @@ Contents |[CVE-2005-2096](https://nvd.nist.gov/vuln/detail/CVE-2005-2096)|Buffer overflow when incomplete code description |[GH-361](https://github.com/zlib-ng/zlib-ng/issues/361)|Test case for overlapping matches| |[GH-364](https://github.com/zlib-ng/zlib-ng/issues/364)|Test case for switching compression levels| +|[GH-382](https://github.com/zlib-ng/zlib-ng/issues/382)|Test case for deflateEnd returning -3 in deflate quick| Copying ------- -Some of the test data in test/data is licensed differently: +Some of the files in _test_ are licensed differently: - - fireworks.jpeg is Copyright 2013 Steinar H. Gunderson, and + - test/data/fireworks.jpeg is Copyright 2013 Steinar H. Gunderson, and is licensed under the Creative Commons Attribution 3.0 license (CC-BY-3.0). See https://creativecommons.org/licenses/by/3.0/ for more information. - - paper-100k.pdf is an excerpt (bytes 92160 to 194560) from the paper + - test/data/paper-100k.pdf is an excerpt (bytes 92160 to 194560) from the paper “Combinatorial Modeling of Chromatin Features Quantitatively Predicts DNA Replication Timing in _Drosophila_” by Federico Comoglio and Renato Paro, which is licensed under the CC-BY license. See http://www.ploscompbiol.org/static/license for more information. - - lcet10.txt is from Project - Gutenberg. It does not have expired copyright, but is still in the - public domain according to the license information. - (http://www.gutenberg.org/ebooks/53). \ No newline at end of file + - test/data/lcet10.txt is from Project Gutenberg. It does not have expired + copyright, but is still in the public domain according to the license information. + (http://www.gutenberg.org/ebooks/53). + + - test/GH-382/defneg3.dat was the smallest file generated by Nathan Moinvaziri + that reproduced GH-382. It is licensed under the terms of the zlib license. diff --git a/test/minideflate.c b/test/minideflate.c new file mode 100644 index 000000000..771e7ff91 --- /dev/null +++ b/test/minideflate.c @@ -0,0 +1,307 @@ +/* minideflate.c -- test deflate/inflate under specific conditions + * Copyright (C) 2020 Nathan Moinvaziri + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +/* =========================================================================== + * deflate() using specialized parameters + */ +void deflate_params(FILE *fin, FILE *fout, int32_t read_buf_size, int32_t write_buf_size, int32_t level, + int32_t window_bits, int32_t mem_level, int32_t strategy, int32_t flush) { + PREFIX3(stream) c_stream; /* compression stream */ + uint8_t *read_buf; + uint8_t *write_buf; + int32_t read; + int err; + + read_buf = (uint8_t *)malloc(read_buf_size); + if (read_buf == NULL) { + fprintf(stderr, "failed to create read buffer (%d)\n", read_buf_size); + return; + } + write_buf = (uint8_t *)malloc(write_buf_size); + if (write_buf == NULL) { + fprintf(stderr, "failed to create write buffer (%d)\n", write_buf_size); + free(read_buf); + return; + } + + c_stream.zalloc = NULL; + c_stream.zfree = NULL; + c_stream.opaque = (void *)0; + c_stream.total_in = 0; + c_stream.total_out = 0; + + err = PREFIX(deflateInit2)(&c_stream, level, Z_DEFLATED, window_bits, mem_level, strategy); + CHECK_ERR(err, "deflateInit2"); + + /* Process input using our read buffer and flush type, + * output to stdout only once write buffer is full */ + do { + read = (int32_t)fread(read_buf, 1, read_buf_size, fin); + if (read <= 0) + break; + + c_stream.next_in = (const uint8_t *)read_buf; + c_stream.next_out = write_buf; + c_stream.avail_in = read; + + do { + c_stream.avail_out = write_buf_size; + err = PREFIX(deflate)(&c_stream, flush); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + + if (c_stream.next_out == write_buf + write_buf_size) { + fwrite(write_buf, 1, write_buf_size, fout); + c_stream.next_out = write_buf; + } + } while (c_stream.next_in < read_buf + read); + } while (err == Z_OK); + + /* Finish the stream if necessary */ + if (flush != Z_FINISH) { + c_stream.avail_in = 0; + do { + if (c_stream.next_out == write_buf + write_buf_size) { + fwrite(write_buf, 1, write_buf_size, fout); + c_stream.next_out = write_buf; + } + + c_stream.avail_out = write_buf_size; + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } while (err == Z_OK); + } + + /* Output remaining data in write buffer */ + if (c_stream.next_out != write_buf) { + fwrite(write_buf, 1, c_stream.next_out - write_buf, fout); + } + + err = PREFIX(deflateEnd)(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + free(read_buf); + free(write_buf); +} + +/* =========================================================================== + * inflate() using specialized parameters + */ +void inflate_params(FILE *fin, FILE *fout, int32_t read_buf_size, int32_t write_buf_size, int32_t window_bits, + int32_t flush) { + PREFIX3(stream) d_stream; /* decompression stream */ + uint8_t *read_buf; + uint8_t *write_buf; + int32_t read; + int err; + + + read_buf = (uint8_t *)malloc(read_buf_size); + if (read_buf == NULL) { + fprintf(stderr, "failed to create read buffer (%d)\n", read_buf_size); + return; + } + write_buf = (uint8_t *)malloc(write_buf_size); + if (write_buf == NULL) { + fprintf(stderr, "failed to create write buffer (%d)\n", write_buf_size); + free(read_buf); + return; + } + + d_stream.zalloc = NULL; + d_stream.zfree = NULL; + d_stream.opaque = (void *)0; + d_stream.total_in = 0; + d_stream.total_out = 0; + + err = PREFIX(inflateInit2)(&d_stream, window_bits); + CHECK_ERR(err, "inflateInit2"); + + /* Process input using our read buffer and flush type, + * output to stdout only once write buffer is full */ + do { + read = (int32_t)fread(read_buf, 1, read_buf_size, fin); + if (read <= 0) + break; + + d_stream.next_in = (const uint8_t *)read_buf; + d_stream.next_out = write_buf; + d_stream.avail_in = read; + + do { + d_stream.avail_out = write_buf_size; + err = PREFIX(inflate)(&d_stream, flush); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + + if (d_stream.next_out == write_buf + write_buf_size) { + fwrite(write_buf, 1, write_buf_size, fout); + d_stream.next_out = write_buf; + } + } while (d_stream.next_in < read_buf + read); + } while (err == Z_OK); + + /* Finish the stream if necessary */ + if (flush != Z_FINISH) { + d_stream.avail_in = 0; + do { + if (d_stream.next_out == write_buf + write_buf_size) { + fwrite(write_buf, 1, write_buf_size, fout); + d_stream.next_out = write_buf; + } + + d_stream.avail_out = write_buf_size; + err = PREFIX(inflate)(&d_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } while (err == Z_OK); + } + + /* Output remaining data in write buffer */ + if (d_stream.next_out != write_buf) { + fwrite(write_buf, 1, d_stream.next_out - write_buf, fout); + } + + err = PREFIX(inflateEnd)(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + free(read_buf); + free(write_buf); +} + +void show_help(void) { + printf("Usage: minideflate [-c] [-f|-h|-R|-F] [-m level] [-r/-t size] [-s flush] [-w bits] [-0 to -9] [input file]\n\n" \ + " -c : write to standard output\n" \ + " -d : decompress\n" \ + " -f : compress with Z_FILTERED\n" \ + " -h : compress with Z_HUFFMAN_ONLY\n" \ + " -R : compress with Z_RLE\n" \ + " -F : compress with Z_FIXED\n" \ + " -m : memory level (1 to 8)\n" \ + " -w : window bits (8 to 15 for gzip, -8 to -15 for zlib)\n" \ + " -s : flush type (0 to 5)\n" \ + " -r : read buffer size\n" \ + " -t : write buffer size\n" \ + " -0 to -9 : compression level\n\n"); +} + +int main(int argc, char **argv) { + int32_t i; + int32_t mem_level = DEF_MEM_LEVEL; + int32_t window_bits = MAX_WBITS; + int32_t strategy = Z_DEFAULT_STRATEGY; + int32_t level = Z_DEFAULT_COMPRESSION; + int32_t read_buf_size = 4096; + int32_t write_buf_size = 4096; + int32_t flush = Z_NO_FLUSH; + uint8_t copyout = 0; + uint8_t uncompr = 0; + char out_file[320]; + FILE *fin = stdin; + FILE *fout = stdout; + + for (i = 1; i < argc; i++) { + if ((strcmp(argv[i], "-m") == 0) && (i + 1 < argc)) + mem_level = atoi(argv[++i]); + else if ((strcmp(argv[i], "-w") == 0) && (i + 1 < argc)) + window_bits = atoi(argv[++i]); + else if ((strcmp(argv[i], "-r") == 0) && (i + 1 < argc)) + read_buf_size = atoi(argv[++i]); + else if ((strcmp(argv[i], "-t") == 0) && (i + 1 < argc)) + write_buf_size = atoi(argv[++i]); + else if ((strcmp(argv[i], "-s") == 0) && (i + 1 < argc)) + flush = atoi(argv[++i]); + else if (strcmp(argv[i], "-c") == 0) + copyout = 1; + else if (strcmp(argv[i], "-d") == 0) + uncompr = 1; + else if (strcmp(argv[i], "-f") == 0) + strategy = Z_FILTERED; + else if (strcmp(argv[i], "-h") == 0) + strategy = Z_HUFFMAN_ONLY; + else if (strcmp(argv[i], "-R") == 0) + strategy = Z_RLE; + else if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9' && argv[i][2] == 0) + level = argv[i][1] - '0'; + else if (strcmp(argv[i], "--help") == 0) { + show_help(); + return 0; + } else if (argv[i][0] == '-') { + show_help(); + return 64; /* EX_USAGE */ + } else + break; + } + + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (i != argc) { + fin = fopen(argv[i], "rb+"); + if (fin == NULL) { + fprintf(stderr, "Failed to open file: %s\n", argv[i]); + exit(1); + } + if (!copyout) { + snprintf(out_file, sizeof(out_file), "%s%s", argv[i], (window_bits < 0) ? ".zz" : ".gz"); + fout = fopen(out_file, "wb"); + if (fout == NULL) { + fprintf(stderr, "Failed to open file: %s\n", out_file); + exit(1); + } + } + } + + if (uncompr) { + inflate_params(fin, fout, read_buf_size, write_buf_size, window_bits, flush); + } else { + deflate_params(fin, fout, read_buf_size, write_buf_size, level, window_bits, mem_level, strategy, flush); + } + + if (fin != stdin) { + fclose(fin); + } + if (fout != stdout) { + fclose(fout); + } + + return 0; +}