]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
longest_match: avoid using negative indices
authorIlya Leoshkevich <iii@linux.ibm.com>
Mon, 24 Jun 2019 14:57:19 +0000 (16:57 +0200)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Thu, 18 Jul 2019 09:22:52 +0000 (11:22 +0200)
Fixes #364

CMakeLists.txt
configure
match_p.h
test/.gitignore
test/GH-364/test.bin [new file with mode: 0644]
test/INDEX
test/Makefile.in
test/switchlevels.c [new file with mode: 0644]

index f33743fbf62cefa284540cf39e9fa88215fef544..f1bcb11674a0980888297532f230530161f5ca34 100644 (file)
@@ -822,6 +822,9 @@ if (ZLIB_ENABLE_TESTS)
     add_executable(minigzip test/minigzip.c)
     configure_test_executable(minigzip)
 
+    add_executable(switchlevels test/switchlevels.c)
+    configure_test_executable(switchlevels)
+
     if(HAVE_OFF64_T)
         add_executable(example64 test/example.c)
         configure_test_executable(example64)
@@ -866,6 +869,13 @@ if (ZLIB_ENABLE_TESTS)
         "-DCOMMAND=${GH_361_COMMAND}"
         -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/test/GH-361/test.txt
         -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake)
+
+    set(GH_364_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:switchlevels> 1 5 9 3)
+    add_test(NAME GH-364
+            COMMAND ${CMAKE_COMMAND}
+            "-DCOMMAND=${GH_364_COMMAND}"
+            -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/test/GH-364/test.bin
+            -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake)
 endif()
 
 FEATURE_SUMMARY(WHAT ALL INCLUDE_QUIET_PACKAGES)
index 5f50a33cb4a1ccb235b9218cdc8844b77f012231..66dfefd3485b4fc3548d8d614e46b441dc634471 100755 (executable)
--- a/configure
+++ b/configure
@@ -1468,6 +1468,7 @@ sed < $SRCDIR/test/Makefile.in "
 /^COMPATTESTS *=/s#=.*#=$COMPATTESTS#
 /^QEMU_RUN *=/s#=.*#=$QEMU_RUN#
 /^WITH_FUZZERS *=/s#=.*#=$with_fuzzers#
+/^LIBNAME *=/s#=.*#=$LIBNAME#
 " > test/Makefile
 
 # create zlib.pc with the configure results
index b956d8d52004283374dc97443daf904fd82d77ad..6dda122b15bd015d3fd9f648992f1fe5fcf7fed3 100644 (file)
--- a/match_p.h
+++ b/match_p.h
@@ -66,7 +66,7 @@ static inline unsigned longest_match(deflate_state *const s, IPos cur_match) {
     /*
      * Do not waste too much time if we already have a good match
      */
-    best_len = s->prev_length;
+    best_len = s->prev_length ? s->prev_length : 1;
     chain_length = s->max_chain_length;
     if (best_len >= s->good_match)
         chain_length >>= 2;
@@ -186,7 +186,7 @@ static inline unsigned longest_match(deflate_state *const s, IPos cur_match) {
     /*
      * Do not waste too much time if we already have a good match
      */
-    best_len = s->prev_length;
+    best_len = s->prev_length ? s->prev_length : 1;
     chain_length = s->max_chain_length;
     if (best_len >= s->good_match)
         chain_length >>= 2;
@@ -385,7 +385,7 @@ static inline unsigned longest_match(deflate_state *const s, IPos cur_match) {
     register unsigned char *scan = window + strstart; /* current string */
     register unsigned char *match;                       /* matched string */
     register unsigned int len;                  /* length of current match */
-    unsigned int best_len = s->prev_length;     /* best match length so far */
+    unsigned int best_len = s->prev_length ? s->prev_length : 1;     /* best match length so far */
     unsigned int nice_match = s->nice_match;    /* stop if match long enough */
     IPos limit = strstart > (IPos)MAX_DIST(s) ?
         strstart - (IPos)MAX_DIST(s) : NIL;
index 2c3af0a08cbd704ebe3768ed66c32854f2d5a8ba..96a3cad0709eeb97af7aab8214aef1f6ea4e57a1 100644 (file)
@@ -1,2 +1,5 @@
 # ignore Makefiles; they're all automatically generated
 Makefile
+/switchlevels
+/switchlevels.dSYM/
+/switchlevels.exe
diff --git a/test/GH-364/test.bin b/test/GH-364/test.bin
new file mode 100644 (file)
index 0000000..1b1cb4d
Binary files /dev/null and b/test/GH-364/test.bin differ
index a1e6b7280888b13e374a6292c7a9fa82e81b74da..9b66ef6cb9500c9ba41f03131f97471f55e58499 100644 (file)
@@ -7,6 +7,8 @@ CVE-2005-1849  :
 CVE-2005-2096  : test cases for the relevant CVEs
 GH-361         : test case for overlapping matches
                  https://github.com/zlib-ng/zlib-ng/issues/361
+GH-364         : test case for switching compression levels
+                 https://github.com/zlib-ng/zlib-ng/issues/364
 
 testCVEinputs.sh: script to run tests for CVEs where input data is supplied
 
index caf49496dbae5aa94c62f85a702ba594313e9baa..79e79e0153c0aa7f752e9fcb66ec7d671b4b0016 100644 (file)
@@ -7,7 +7,8 @@ CFLAGS=
 EXE=
 SRCDIR=
 SRCTOP=
-TEST_LDFLAGS=-L.. ../libz.a
+LIBNAME=
+TEST_LDFLAGS=-L.. ../$(LIBNAME).a
 WITH_FUZZERS=
 
 COMPATTESTS =
@@ -97,15 +98,22 @@ CVE-2003-0107$(EXE): CVE-2003-0107.o
        $(CC) $(CFLAGS) -o $@ CVE-2003-0107.o $(TEST_LDFLAGS)
 
 .PHONY: ghtests
-ghtests: testGH-361
+ghtests: testGH-361 testGH-364
 
 .PHONY: testGH-361
 testGH-361:
        $(QEMU_RUN) ../minigzip$(EXE) -4 <$(SRCDIR)/GH-361/test.txt >/dev/null
 
+switchlevels$(EXE): $(SRCDIR)/switchlevels.c
+       $(CC) $(CFLAGS) -I.. -I$(SRCTOP) -o $@ $< $(TEST_LDFLAGS)
+
+.PHONY: testGH-364
+testGH-364: switchlevels$(EXE)
+       $(QEMU_RUN) ./switchlevels$(EXE) 1 5 9 3 <$(SRCDIR)/GH-364/test.bin >/dev/null
+
 clean:
        rm -f *.o *.gcda *.gcno *.gcov
-       rm -f CVE-2003-0107$(EXE)
+       rm -f CVE-2003-0107$(EXE) switchlevels$(EXE)
 
 distclean:
        rm -f Makefile
diff --git a/test/switchlevels.c b/test/switchlevels.c
new file mode 100644 (file)
index 0000000..67bb152
--- /dev/null
@@ -0,0 +1,112 @@
+/* Compresses a user-specified number of chunks from stdin into stdout as a single gzip stream.
+ * Each chunk is compressed with a user-specified level.
+ */
+
+#include "zbuild.h"
+#ifdef ZLIB_COMPAT
+#  include "zlib.h"
+#else
+#  include "zlib-ng.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int read_all(unsigned char *buf, size_t size)
+{
+    for (size_t total_read = 0; total_read < size;) {
+        size_t n_read = fread(buf + total_read, 1, size - total_read, stdin);
+        if (ferror(stdin)) {
+            perror("fread\n");
+            return 1;
+        }
+        if (n_read == 0) {
+            fprintf(stderr, "Premature EOF\n");
+            return 1;
+        }
+        total_read += n_read;
+    }
+    return 0;
+}
+
+static int write_all(unsigned char *buf, size_t size)
+{
+    for (size_t total_written = 0; total_written < size;) {
+        size_t n_written = fwrite(buf + total_written, 1, size - total_written, stdout);
+        if (ferror(stdout)) {
+            perror("fwrite\n");
+            return 1;
+        }
+        total_written += n_written;
+    }
+    return 0;
+}
+
+static int compress_chunk(PREFIX3(stream) *strm, int level, int size, int last)
+{
+    int ret = 1;
+    int err = PREFIX(deflateParams)(strm, level, Z_DEFAULT_STRATEGY);
+    if (err != Z_OK) {
+        fprintf(stderr, "deflateParams() failed with code %d\n", err);
+        goto done;
+    }
+    unsigned long compsize = 100 + 2 * PREFIX(deflateBound)(strm, size);
+    unsigned char *buf = malloc(size + compsize);
+    if (buf == NULL) {
+        fprintf(stderr, "Out of memory\n");
+        goto done;
+    }
+    if (read_all(buf, size) != 0) {
+        goto free_buf;
+    }
+    strm->next_in = buf;
+    strm->avail_in = size;
+    strm->next_out = buf + size;
+    strm->avail_out = compsize;
+    err = PREFIX(deflate)(strm, last ? Z_FINISH : Z_SYNC_FLUSH);
+    if ((!last && err != Z_OK) || (last && err != Z_STREAM_END)) {
+        fprintf(stderr, "deflate() failed with code %d\n", err);
+        goto free_buf;
+    }
+    if (strm->avail_in != 0) {
+        fprintf(stderr, "deflate() did not consume %d bytes of input\n", strm->avail_in);
+        goto free_buf;
+    }
+    if (write_all(buf + size, compsize - strm->avail_out) != 0) {
+        goto free_buf;
+    }
+    ret = 0;
+free_buf:
+    free(buf);
+done:
+    return ret;
+}
+
+/* ===========================================================================
+ * Usage:  switchlevels level1 size1 [level2 size2 ...]
+ */
+
+int main(int argc, char **argv)
+{
+    int ret = EXIT_FAILURE;
+    PREFIX3(stream) strm;
+    memset(&strm, 0, sizeof(strm));
+    int err = PREFIX(deflateInit2)(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY);
+    if (err != Z_OK) {
+        fprintf(stderr, "deflateInit() failed with code %d\n", err);
+        goto done;
+    }
+    for (int i = 1; i < argc - 1; i += 2) {
+        int level = atoi(argv[i]);
+        int size = atoi(argv[i + 1]);
+        if (compress_chunk(&strm, level, size, i + 2 >= argc - 1) != 0) {
+            goto deflate_end;
+        }
+    }
+    ret = EXIT_SUCCESS;
+deflate_end:
+    PREFIX(deflateEnd)(&strm);
+done:
+    return ret;
+}