]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Added regression test for deflateEnd returning -3 when using deflate quick. #382
authorNathan Moinvaziri <nathan@solidstatenetworks.com>
Sat, 26 Oct 2019 20:03:25 +0000 (13:03 -0700)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Tue, 16 Jun 2020 14:08:41 +0000 (16:08 +0200)
CMakeLists.txt
test/GH-382/defneg3.dat [new file with mode: 0644]
test/README.md
test/minideflate.c [new file with mode: 0644]

index a54dda5d5d3b6ae68083af1648dece65bfd0eebc..c4b056b037c7d546bb2a548a268d5ed8950da90a 100644 (file)
@@ -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} $<TARGET_FILE:minideflate> -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} $<TARGET_FILE:minideflate> -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} $<TARGET_FILE:switchlevels> 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 (file)
index 0000000..5fa6a08
--- /dev/null
@@ -0,0 +1 @@
+oÌ\99Ì?ÌOÌÃÌḩÌÕÌ>Ì\17Ì\7fÌàÌ\9d̹Ì\98ÌÔÌEÌsÌ\97Ì\8dÌ4Ì\99Ì\91Ì¢Ì6Ì\14ÌØÌæÌ\Ì\aÌ\14Ì5̪̲Ì\95ÌmÌ\10Ì\96Ìç̺Ì\9cÌÙ̧Ì\17ÌíÌíÌ\96Ì\11ÌëÌmÌìÌÎ̵ÌGÌïÌOÌÛÌ ÌÃÌòÌÎÌôÌ\84Ì;Ì\94ÌýÌ\92ÌÓÌÀÌ×Ì,ÌÑÌ¢ÌáÌAÌ9Ì»ÌæÌ\82ÌÂÌsÌý̼ÌÝÌ\ fÌ­ÌeÌòÌÝÌUÌuÌí̱ÌËÌwÌùÌ\95ÌDÌßÌ\8b̽ÌtÌ\9ẹ̹ÌöÌôÌOÌîÌíÌ\85ÌpÌGÌḭ̀ÌÀÌ(Ì\13Ì\1cÌ\14̤Ì{Ì\93ÌßÌïÌÕÌ\14ÌøÌ\16ÌMÌ#Ì\9dÌí̵ÌdÌ·ÌIÌßÌhÌ_ÌpÌJÌÇÌ¢ÌÎÌ\ 1ÌoÌ\81ÌêÌÁÌ;Ì<Ì\98ÌZÌÈÌÑÌoÌWÌ\84Ì¿Ì}ÌáÌ\aÌ\ fÌ:Ìá̧Ì\95Ì»ÌeÌFÌtÌ(ÌEÌoÌàÌpÌ\ 6Ì¢Ì(Ì;ÌþÌëÌóÌ!̹̹ÌÉÌ\19Ì\9cÌîÌÖÌ4ÌÈÌ3ÌëÌ\8bÌBÌ\8eÌÆÌuÌPÌ6Ì\93ÌþÌ&̦̳Ì\95ÌÁÌðÌ»Ì\ 5Ì\14ÌTÌÀ̧ÌbÌ\11ÌÒÌÕÌëÌ{ÌÆÌ¡ÌÊÌNÌ9ÌÇÌ\1eÌBÌÑ
\ No newline at end of file
index 095f4dc7da694097700564e26d4e0e454cf862e9..247d5bac742fb323f5843fd4d71923f8816a9ed1 100644 (file)
@@ -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 (file)
index 0000000..771e7ff
--- /dev/null
@@ -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 <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "zbuild.h"
+#ifdef ZLIB_COMPAT
+#  include "zlib.h"
+#else
+#  include "zlib-ng.h"
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+#  include <fcntl.h>
+#  include <io.h>
+#  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;
+}