Added regression test for deflateEnd returning -3 when using deflate quick. #382

This commit is contained in:
Nathan Moinvaziri 2019-10-26 13:03:25 -07:00 committed by Hans Kristian Rosbach
parent 959eda5c15
commit b6136c629c
4 changed files with 343 additions and 7 deletions

View 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}

1
test/GH-382/defneg3.dat Normal file
View File

@ -0,0 +1 @@
oフ厠?フOフテフhファフユフ>フフ猯變ケフ侘ヤフEフsフ領採4フ厠体「フ6フフリフ賣\フフ5フェフイフ蔑mフフ摸醂コフ慘ルファフフ﨓﨓摸<>mフ<6D>ホフオフGフ<47>Oフロフ フテフ<EFBE83>ホフ<EFBE8E><EFBE8C>;フ販<EFBE8C>フ栂モフタフラフ,フムフ「フ睥Aフ9フサフ賣のツフsフ<73>フシフンフフュフeフ<65>ンフUフuフ﨓アフヒフwフ<77>蔑Dプフ粁スフtフ槊」フケフ<EFBDB9><EFBE8C>Oフ閒﨓<E99692>pフGフ<47>ーフタフ(フフ、フ{フ椴゚フ<EFBE9F>ユフ<>フMフ#フ變﨓オフdフキフIプフhフ_フpフJフヌフ「フホフフoフ⇔<EFBE8C>チフ;フ<フ侘ZフネフムフoフWフ<57>ソフ}フ睥フ:フ睥ァフ蔑サフeフFフtフ(フEフoフ猯pフフ「フ(フ;フ<><EFBFBD><EFBE8C>!フケフケフノフフ慘閒ヨフ4フネフ3フ<33>粁Bフ捨ニフuフPフ6フ椴<EFBE8C>フ&フヲフウフ蔑チフ<EFBE81>サフフTフタファフbフフメフユフ<EFBE95>{フニフ。フハフNフ9フヌフフBフム

View 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).
- 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.

307
test/minideflate.c Normal file
View File

@ -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;
}