Commit 6995c67 for zlib

commit 6995c67bd443bc982771b043ef3be3591cc522d0
Author: Mark Adler <git@madler.net>
Date:   Sun Sep 20 17:28:56 2026 -0700

    Avoid signed-overflow undefined behaviors in gzseek.

diff --git a/gzguts.h b/gzguts.h
index 55a69d9..5a57b94 100644
--- a/gzguts.h
+++ b/gzguts.h
@@ -228,3 +228,10 @@ char ZLIB_INTERNAL *gz_strwinerror(DWORD error);
    (possible z_off64_t types off_t, off64_t, and long are all signed) */
 unsigned ZLIB_INTERNAL gz_intmax(void);
 #define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
+
+/* largest value representable in z_off64_t */
+#ifndef CHAR_BIT
+#  define CHAR_BIT 8
+#endif
+#define GZ_OFF_MAX \
+    ((((z_off64_t)1 << (sizeof(z_off64_t) * CHAR_BIT - 2)) - 1) * 2 + 1)
diff --git a/gzlib.c b/gzlib.c
index 67900b6..0a928be 100644
--- a/gzlib.c
+++ b/gzlib.c
@@ -366,7 +366,7 @@ int ZEXPORT gzrewind(gzFile file) {
 /* -- see zlib.h -- */
 z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
     unsigned n;
-    z_off64_t ret;
+    z_off64_t ret, pos;
     gz_statep state;

     /* get internal structure and check integrity */
@@ -384,18 +384,21 @@ z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
     if (whence != SEEK_SET && whence != SEEK_CUR)
         return -1;

-    /* normalize offset to a SEEK_CUR specification */
-    if (whence == SEEK_SET)
-        offset -= state->x.pos;
-    else {
-        offset += state->past ? 0 : state->skip;
+    /* compute the absolute position */
+    pos = whence == SEEK_SET ? 0 :
+          state->x.pos + (state->past ? 0 : state->skip);
+    if (offset > GZ_OFF_MAX - pos)
+        return -1;                          /* would overflow z_off64_t */
+    if (whence != SEEK_SET)
         state->skip = 0;
-    }
+    if (offset < -pos)
+        return -1;                          /* before start of file */
+    pos += offset;

     /* if within raw area while reading, just go there */
-    if (state->mode == GZ_READ && state->how == COPY &&
-            state->x.pos + offset >= 0) {
-        ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
+    if (state->mode == GZ_READ && state->how == COPY) {
+        ret = LSEEK(state->fd, pos - state->x.pos - (z_off64_t)state->x.have,
+                    SEEK_CUR);
         if (ret == -1)
             return -1;
         state->x.have = 0;
@@ -404,20 +407,18 @@ z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
         state->skip = 0;
         gz_error(state, Z_OK, NULL);
         state->strm.avail_in = 0;
-        state->x.pos += offset;
-        return state->x.pos;
+        state->x.pos = pos;
+        return pos;
     }

-    /* calculate skip amount, rewinding if needed for back seek when reading */
-    if (offset < 0) {
+    /* rewind if needed for back seek when reading */
+    if (pos < state->x.pos) {
         if (state->mode != GZ_READ)         /* writing -- can't go backwards */
             return -1;
-        offset += state->x.pos;
-        if (offset < 0)                     /* before start of file! */
-            return -1;
-        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
+        if (gzrewind(file) == -1)           /* rewind, then skip to pos */
             return -1;
     }
+    offset = pos - state->x.pos;

     /* if reading, skip what's in output buffer (one less gzgetc() check) */
     if (state->mode == GZ_READ) {
@@ -431,7 +432,7 @@ z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {

     /* request skip (if not zero) */
     state->skip = offset;
-    return state->x.pos + offset;
+    return pos;
 }

 /* -- see zlib.h -- */
diff --git a/zlib.h b/zlib.h
index e51097d..c104b14 100644
--- a/zlib.h
+++ b/zlib.h
@@ -1677,7 +1677,8 @@ ZEXTERN z_off_t ZEXPORT gzseek(gzFile file,
      gzseek returns the resulting offset location as measured in bytes from
    the beginning of the uncompressed stream, or -1 in case of error, in
    particular if the file is opened for writing and the new starting position
-   would be before the current position.
+   would be before the current position, or if the resulting position would
+   not be representable in the offset type.
 */

 ZEXTERN int ZEXPORT gzrewind(gzFile file);