Commit 647a8c3 for zlib
commit 647a8c38a0a67b6327978c9a978aaadd84b5908b
Author: Mark Adler <git@madler.net>
Date: Sun Oct 25 17:59:59 2026 -0700
Set dest->state to Z_NULL when a stream copy fails.
This makes deflateEnd() and inflateEnd() safe after a failed copy.
This also fixes the code to meet the promise in zlib.h to leave
msg unchanged.
diff --git a/deflate.c b/deflate.c
index da06c1c..daa16e1 100644
--- a/deflate.c
+++ b/deflate.c
@@ -1317,39 +1317,49 @@ int ZEXPORT deflateEnd(z_streamp strm) {
*/
int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
#ifdef MAXSEG_64K
- (void)dest;
(void)source;
+ if (dest != Z_NULL)
+ dest->state = Z_NULL;
return Z_STREAM_ERROR;
#else
deflate_state *ds;
deflate_state *ss;
-
- if (deflateStateCheck(source) || dest == Z_NULL) {
+ if (dest == Z_NULL)
+ return Z_STREAM_ERROR;
+ if (deflateStateCheck(source)) {
+ dest->state = Z_NULL;
return Z_STREAM_ERROR;
}
ss = source->state;
- zmemcpy(dest, source, sizeof(z_stream));
-
- ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
- if (ds == Z_NULL) return Z_MEM_ERROR;
- zmemzero(ds, sizeof(deflate_state));
- dest->state = (struct internal_state FAR *) ds;
+ ds = (deflate_state *) ZALLOC(source, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) {
+ dest->state = Z_NULL;
+ return Z_MEM_ERROR;
+ }
zmemcpy(ds, ss, sizeof(deflate_state));
- ds->strm = dest;
-
- ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
- ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
- ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
- ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS);
-
+ ds->window = (Bytef *) ZALLOC(source, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(source, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(source, ds->hash_size, sizeof(Pos));
+ ds->pending_buf = (uchf *) ZALLOC(source, ds->lit_bufsize, LIT_BUFS);
if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
ds->pending_buf == Z_NULL) {
- deflateEnd (dest);
+ TRY_FREE(source, ds->pending_buf);
+ TRY_FREE(source, ds->head);
+ TRY_FREE(source, ds->prev);
+ TRY_FREE(source, ds->window);
+ ZFREE(source, ds);
+ dest->state = Z_NULL;
return Z_MEM_ERROR;
}
+
+ /* copy the stream and attach the new state */
+ zmemcpy(dest, source, sizeof(z_stream));
+ dest->state = (struct internal_state FAR *) ds;
+ ds->strm = dest;
+
/* following zmemcpy's do not work for 16-bit MSDOS */
zmemcpy(ds->window, ss->window, ss->high_water);
zmemcpy(ds->prev, ss->prev,
diff --git a/inflate.c b/inflate.c
index 5f5d492..d8bcab8 100644
--- a/inflate.c
+++ b/inflate.c
@@ -1331,14 +1331,21 @@ int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
unsigned char FAR *window;
/* check input */
- if (inflateStateCheck(source) || dest == Z_NULL)
+ if (dest == Z_NULL)
return Z_STREAM_ERROR;
+ if (inflateStateCheck(source)) {
+ dest->state = Z_NULL;
+ return Z_STREAM_ERROR;
+ }
state = (struct inflate_state FAR *)source->state;
/* allocate space */
copy = (struct inflate_state FAR *)
ZALLOC(source, 1, sizeof(struct inflate_state));
- if (copy == Z_NULL) return Z_MEM_ERROR;
+ if (copy == Z_NULL) {
+ dest->state = Z_NULL;
+ return Z_MEM_ERROR;
+ }
zmemzero(copy, sizeof(struct inflate_state));
window = Z_NULL;
if (state->window != Z_NULL) {
@@ -1346,6 +1353,7 @@ int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
if (window == Z_NULL) {
ZFREE(source, copy);
+ dest->state = Z_NULL;
return Z_MEM_ERROR;
}
}
diff --git a/zlib.h b/zlib.h
index 2cbdeca..63b2f32 100644
--- a/zlib.h
+++ b/zlib.h
@@ -696,7 +696,9 @@ ZEXTERN int ZEXPORT deflateCopy(z_streamp dest,
deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
(such as zalloc being Z_NULL). msg is left unchanged in both source and
- destination.
+ destination. If deflateCopy fails and dest is not Z_NULL, then dest->state
+ is set to Z_NULL with dest otherwise unchanged, so that deflateEnd(dest) can
+ be called safely, though dest is not a usable stream.
*/
ZEXTERN int ZEXPORT deflateReset(z_streamp strm);
@@ -980,7 +982,9 @@ ZEXTERN int ZEXPORT inflateCopy(z_streamp dest,
inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
(such as zalloc being Z_NULL). msg is left unchanged in both source and
- destination.
+ destination. If inflateCopy fails and dest is not Z_NULL, then dest->state
+ is set to Z_NULL with dest otherwise unchanged, so that inflateEnd(dest) can
+ be called safely, though dest is not a usable stream.
*/
ZEXTERN int ZEXPORT inflateReset(z_streamp strm);