Subject: [PATCH] Fixed DFLTCC compression level switching issues --- configure | 4 +-- contrib/s390/dfltcc.c | 52 ++++++++++++++++++++++++++++++----- contrib/s390/dfltcc_deflate.h | 2 ++ deflate.c | 12 ++++---- test/infcover.c | 2 +- 5 files changed, 57 insertions(+), 15 deletions(-) diff --git a/configure b/configure index bfe4386..70ed86b 100755 --- a/configure +++ b/configure @@ -139,7 +139,7 @@ case "$1" in -w* | --warn) warn=1; shift ;; -d* | --debug) debug=1; shift ;; --dfltcc) - CFLAGS="$CFLAGS -DDFLTCC" + CFLAGS="$CFLAGS -DDFLTCC -DDFLTCC_LEVEL_MASK=0x7e" OBJC="$OBJC dfltcc.o" PIC_OBJC="$PIC_OBJC dfltcc.lo" shift @@ -838,7 +838,7 @@ cat > $test.c << EOF #include int main() { return 0; } EOF -if try ${CC} ${CFLAGS} $test.c; then + if try $CC -c $CFLAGS $test.c; then echo "Checking for sys/sdt.h ... Yes." | tee -a configure.log CFLAGS="$CFLAGS -DHAVE_SYS_SDT_H" SFLAGS="$SFLAGS -DHAVE_SYS_SDT_H" diff --git a/contrib/s390/dfltcc.c b/contrib/s390/dfltcc.c index d88a0d6..94a196f 100644 --- a/contrib/s390/dfltcc.c +++ b/contrib/s390/dfltcc.c @@ -350,8 +350,12 @@ int ZLIB_INTERNAL dfltcc_deflate(strm, flush, result) int soft_bcc; int no_flush; - if (!dfltcc_can_deflate(strm)) + if (!dfltcc_can_deflate(strm)) { + /* Clear history. */ + if (flush == Z_FULL_FLUSH) + param->hl = 0; return 0; + } again: masked_avail_in = 0; @@ -376,7 +380,8 @@ again: /* Clear history. */ if (flush == Z_FULL_FLUSH) param->hl = 0; - *result = need_more; + /* Trigger block post-processing if necessary. */ + *result = no_flush ? need_more : block_done; return 1; } @@ -403,13 +408,18 @@ again: param->bcf = 0; dfltcc_state->block_threshold = strm->total_in + dfltcc_state->block_size; - if (strm->avail_out == 0) { - *result = need_more; - return 1; - } } } + /* No space for compressed data. If we proceed, dfltcc_cmpr() will return + * DFLTCC_CC_OP1_TOO_SHORT without buffering header bits, but we will still + * set BCF=1, which is wrong. Avoid complications and return early. + */ + if (strm->avail_out == 0) { + *result = need_more; + return 1; + } + /* The caller gave us too much data. Pass only one block worth of * uncompressed data to DFLTCC and mask the rest, so that on the next * iteration we start a new block. @@ -737,10 +747,15 @@ __attribute__((constructor)) local void init_globals(void) * compiling with -m31, gcc defaults to ESA mode, however, since the kernel * is 64-bit, it's always z/Architecture mode at runtime. */ - __asm__ volatile(".machinemode push\n" + __asm__ volatile( +#ifndef __clang__ + ".machinemode push\n" ".machinemode zarch\n" +#endif "stfle %[facilities]\n" +#ifndef __clang__ ".machinemode pop\n" +#endif : [facilities] "=Q" (cpu_facilities) , [r0] "+r" (r0) : @@ -872,6 +887,28 @@ int ZLIB_INTERNAL dfltcc_deflate_params(strm, level, strategy, flush) return Z_OK; } +int ZLIB_INTERNAL dfltcc_deflate_done(strm, flush) + z_streamp strm; + int flush; +{ + deflate_state FAR *state = (deflate_state FAR *)strm->state; + struct dfltcc_state FAR *dfltcc_state = GET_DFLTCC_STATE(state); + struct dfltcc_param_v0 FAR *param = &dfltcc_state->param; + + /* When deflate(Z_FULL_FLUSH) is called with small avail_out, it might + * close the block without resetting the compression state. Detect this + * situation and return that deflation is not done. + */ + if (flush == Z_FULL_FLUSH && strm->avail_out == 0) + return 0; + + /* Return that deflation is not done if DFLTCC is used and either it + * buffered some data (Continuation Flag is set), or has not written EOBS + * yet (Block-Continuation Flag is set). + */ + return !dfltcc_can_deflate(strm) || (!param->cf && !param->bcf); +} + /* Preloading history. */ @@ -925,6 +962,7 @@ int ZLIB_INTERNAL dfltcc_deflate_set_dictionary(strm, dictionary, dict_length) append_history(param, state->window, dictionary, dict_length); state->strstart = 1; /* Add FDICT to zlib header */ + state->block_start = state->strstart; /* Make deflate_stored happy */ return Z_OK; } diff --git a/contrib/s390/dfltcc_deflate.h b/contrib/s390/dfltcc_deflate.h index de36784..914daa4 100644 --- a/contrib/s390/dfltcc_deflate.h +++ b/contrib/s390/dfltcc_deflate.h @@ -11,6 +11,7 @@ int ZLIB_INTERNAL dfltcc_deflate_params OF((z_streamp strm, int level, int strategy, int *flush)); +int ZLIB_INTERNAL dfltcc_deflate_done OF((z_streamp strm, int flush)); int ZLIB_INTERNAL dfltcc_deflate_set_dictionary OF((z_streamp strm, const Bytef *dictionary, uInt dict_length)); @@ -41,6 +42,7 @@ int ZLIB_INTERNAL dfltcc_deflate_get_dictionary OF((z_streamp strm, if (err == Z_STREAM_ERROR) \ return err; \ } while (0) +#define DEFLATE_DONE dfltcc_deflate_done #define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, source_len) \ do { \ if (dfltcc_can_deflate((strm))) \ diff --git a/deflate.c b/deflate.c index d907a1b..085abbe 100644 --- a/deflate.c +++ b/deflate.c @@ -75,6 +75,7 @@ const char deflate_copyright[] = #define DEFLATE_GET_DICTIONARY_HOOK(strm, dict, dict_len) do {} while (0) #define DEFLATE_RESET_KEEP_HOOK(strm) do {} while (0) #define DEFLATE_PARAMS_HOOK(strm, level, strategy, hook_flush) do {} while (0) +#define DEFLATE_DONE(strm, flush) 1 #define DEFLATE_BOUND_ADJUST_COMPLEN(strm, complen, sourceLen) do {} while (0) #define DEFLATE_NEED_CONSERVATIVE_BOUND(strm) 0 #define DEFLATE_HOOK(strm, flush, bstate) 0 @@ -605,14 +606,15 @@ int ZEXPORT deflateParams(strm, level, strategy) DEFLATE_PARAMS_HOOK(strm, level, strategy, &hook_flush); func = configuration_table[s->level].func; - if ((strategy != s->strategy || func != configuration_table[level].func || - hook_flush != Z_NO_FLUSH) && s->last_flush != -2) { + if (((strategy != s->strategy || func != configuration_table[level].func) && + s->last_flush != -2) || hook_flush != Z_NO_FLUSH) { /* Flush the last buffer: */ - int err = deflate(strm, RANK(hook_flush) > RANK(Z_BLOCK) ? - hook_flush : Z_BLOCK); + int flush = RANK(hook_flush) > RANK(Z_BLOCK) ? hook_flush : Z_BLOCK; + int err = deflate(strm, flush); if (err == Z_STREAM_ERROR) return err; - if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) + if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead || + !DEFLATE_DONE(strm, flush)) return Z_BUF_ERROR; } if (s->level != level) { diff --git a/test/infcover.c b/test/infcover.c index a34cd17..a208219 100644 --- a/test/infcover.c +++ b/test/infcover.c @@ -373,7 +373,7 @@ local void cover_support(void) mem_setup(&strm); strm.avail_in = 0; strm.next_in = Z_NULL; - ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream)); + ret = inflateInit_(&strm, &ZLIB_VERSION[1], (int)sizeof(z_stream)); assert(ret == Z_VERSION_ERROR); mem_done(&strm, "wrong version"); -- 2.26.0