From 936d003852c8f718c862705722b66728d684a3da Mon Sep 17 00:00:00 2001 From: Girma Metaferia Date: Sun, 30 Aug 2026 05:25:26 -0400 Subject: [PATCH] Avoid overflow after a stalled gzprintf write. --- gzwrite.c | 5 ++++ test/CMakeLists.txt | 6 +++++ test/gzprintfwrite.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 test/gzprintfwrite.c diff --git a/gzwrite.c b/gzwrite.c index b5026e5fad..86cacefc0a 100644 --- a/gzwrite.c +++ b/gzwrite.c @@ -211,6 +211,11 @@ local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) { state->strm.next_in = state->in; have = (unsigned)((state->strm.next_in + state->strm.avail_in) - state->in); + if (have >= state->size) { + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->again ? put - len : 0; + continue; + } copy = state->size - have; if (copy > len) copy = (unsigned)len; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0ee08695c4..1e21adaccf 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -69,6 +69,12 @@ if(ZLIB_BUILD_STATIC) $<$:HAVE_HIDDEN>) add_test(NAME zlib_examplestatic COMMAND zlib_examplestatic) + if(UNIX) + add_executable(zlib_gzprintfwrite gzprintfwrite.c) + target_link_libraries(zlib_gzprintfwrite ZLIB::ZLIBSTATIC) + add_test(NAME zlib_gzprintfwrite COMMAND zlib_gzprintfwrite) + endif(UNIX) + add_executable(zlib_minigzipstatic minigzip.c) target_link_libraries(zlib_minigzipstatic ZLIB::ZLIBSTATIC) set_target_properties(zlib_minigzipstatic diff --git a/test/gzprintfwrite.c b/test/gzprintfwrite.c new file mode 100644 index 0000000000..16fcd21daf --- /dev/null +++ b/test/gzprintfwrite.c @@ -0,0 +1,55 @@ +/* gzprintfwrite.c -- test a non-blocking gzprintf followed by gzwrite + * Copyright (C) 2026 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zlib.h" +#include +#include +#include +#include +#include + +int main(void) { + int pipefd[2]; + unsigned char fill[4096]; + gzFile file; + int put; + + if (pipe(pipefd) == -1 || + fcntl(pipefd[1], F_SETFL, + fcntl(pipefd[1], F_GETFL) | O_NONBLOCK) == -1) { + perror("pipe"); + return 1; + } + + memset(fill, 0xa5, sizeof(fill)); + while (write(pipefd[1], fill, sizeof(fill)) > 0) + ; + if (errno != EAGAIN && errno != EWOULDBLOCK) { + perror("fill pipe"); + return 1; + } + + file = gzdopen(pipefd[1], "wbN"); + if (file == NULL || gzbuffer(file, 8) != 0) { + fprintf(stderr, "gzip setup failed\n"); + return 1; + } + + if (gzprintf(file, "%s", "123456") != 6 || + gzprintf(file, "%s", "abcdef") != 6) { + fprintf(stderr, "gzprintf did not reach the expected stalled state\n"); + return 1; + } + + put = gzwrite(file, "ABCDEFG", 7); + if (put != 0) { + fprintf(stderr, "gzwrite consumed input while the gzip input buffer was stalled: %d\n", put); + return 1; + } + + (void)gzclose(file); + close(pipefd[0]); + return 0; +}