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);