aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/nifs/common/zlib_nif.c
diff options
context:
space:
mode:
authorJohn Högberg <[email protected]>2017-11-07 17:24:55 +0100
committerJohn Högberg <[email protected]>2017-11-09 08:23:20 +0100
commit8cfe9496873fa36eccda939e56bf7a922e945ca9 (patch)
tree0b7c43c6c45fd0e87e680f734c0ceb0187c95187 /erts/emulator/nifs/common/zlib_nif.c
parent3e8c1ff94c0a73df71daadd4eb782c21c49f22d9 (diff)
downloadotp-8cfe9496873fa36eccda939e56bf7a922e945ca9.tar.gz
otp-8cfe9496873fa36eccda939e56bf7a922e945ca9.tar.bz2
otp-8cfe9496873fa36eccda939e56bf7a922e945ca9.zip
Fix deflateParams on zlib 1.2.11
1.2.11 started bailing when avail_out==0 regardless of whether there's anything to flush or not, and there's no point in adapting the old method since it was vulnerable to bugs in other zlib versions which updated the deflate parameters even on failure. The api_deflateParams test has been expanded accordingly, and two white-box cases in zip_usage has been updated to make fewer assumptions about the output; the validity of the compressed data is what matters, not whether it's exactly the same as the test vector.
Diffstat (limited to 'erts/emulator/nifs/common/zlib_nif.c')
-rw-r--r--erts/emulator/nifs/common/zlib_nif.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/erts/emulator/nifs/common/zlib_nif.c b/erts/emulator/nifs/common/zlib_nif.c
index fa29b4fb71..9565a5a059 100644
--- a/erts/emulator/nifs/common/zlib_nif.c
+++ b/erts/emulator/nifs/common/zlib_nif.c
@@ -717,7 +717,9 @@ static ERL_NIF_TERM zlib_deflateEnd(ErlNifEnv *env, int argc, const ERL_NIF_TERM
static ERL_NIF_TERM zlib_deflateParams(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
zlib_data_t *d;
+
int res, level, strategy;
+ Bytef dummy_buffer;
if(argc != 3 || !get_zlib_data(env, argv[0], &d)
|| !enif_get_int(env, argv[1], &level)
@@ -729,12 +731,27 @@ static ERL_NIF_TERM zlib_deflateParams(ErlNifEnv *env, int argc, const ERL_NIF_T
return enif_raise_exception(env, am_not_initialized);
}
- /* deflateParams will flush everything currently in the stream, corrupting
- * the heap unless it's empty. We therefore pretend to have a full output
- * buffer, forcing a Z_BUF_ERROR if there's anything left to be flushed. */
- d->s.avail_out = 0;
+ /* This is a bit of a hack; deflateParams flushes with Z_BLOCK which won't
+ * stop at a byte boundary, so we can't split this operation up, and we
+ * can't allocate a buffer large enough to fit it in one go since we have
+ * to support zlib versions that lack deflatePending.
+ *
+ * We therefore flush everything prior to this call to ensure that we are
+ * stopped on a byte boundary and have no pending data. We then hand it a
+ * dummy buffer to detect when this assumption doesn't hold (Hopefully
+ * never), and to smooth over an issue with zlib 1.2.11 which always
+ * returns Z_BUF_ERROR when d->s.avail_out is 0, regardless of whether
+ * there's any pending data or not. */
+
+ d->s.next_out = &dummy_buffer;
+ d->s.avail_out = 1;
+
res = deflateParams(&d->s, level, strategy);
+ if(d->s.avail_out == 0) {
+ return zlib_return(env, Z_STREAM_ERROR);
+ }
+
return zlib_return(env, res);
}