From 8cd91168dc2c49c6b5cfaa73e886331402578951 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 31 Jul 2026 10:37:09 +0200 Subject: [PATCH 1/4] [zip] add missing argument to R__lm_free It must be called at the end of zipping to free dynamically allocated buffer. And necessary pointer was missing. Seems to be it was never build with DYN_ALLOC defines --- core/zip/src/ZDeflate.c | 4 +++- core/zip/src/ZIP.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/zip/src/ZDeflate.c b/core/zip/src/ZDeflate.c index 38c5580837959..0f669291041ad 100644 --- a/core/zip/src/ZDeflate.c +++ b/core/zip/src/ZDeflate.c @@ -301,7 +301,7 @@ int R__lm_init (bits_internal_state *state, int pack_level, ush *flags) /* =========================================================================== * Free the window and hash table */ -void R__lm_free() +void R__lm_free(bits_internal_state *state) { #ifdef DYN_ALLOC if (state->R__window != NULL) { @@ -313,6 +313,8 @@ void R__lm_free() fcfree(state->R__head); state->R__prev = state->R__head = NULL; } +#else + (void) state; #endif /* DYN_ALLOC */ } diff --git a/core/zip/src/ZIP.h b/core/zip/src/ZIP.h index 3cbc260b6554f..29b911a9e1bd7 100644 --- a/core/zip/src/ZIP.h +++ b/core/zip/src/ZIP.h @@ -100,7 +100,7 @@ typedef struct tree_internal_state tree_internal_state; /* in deflate.c */ int R__lm_init OF((bits_internal_state *state,int pack_level, ush *flags)); -void R__lm_free OF((void)); +void R__lm_free OF((bits_internal_state *state)); ulg R__Deflate OF((bits_internal_state *state,int *errorflag)); /* in trees.c */ From c45219ee334f8f96639fa52a479a64e541d68da9 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 31 Jul 2026 10:39:03 +0200 Subject: [PATCH 2/4] [zip] add R__lm_free call R__zipOld If dynamic memory allocated, it must be freed at the end --- core/zip/src/RZip.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/zip/src/RZip.cxx b/core/zip/src/RZip.cxx index 38b020a3459c7..a4daab08756db 100644 --- a/core/zip/src/RZip.cxx +++ b/core/zip/src/RZip.cxx @@ -167,6 +167,9 @@ static void R__zipOld(int cxlevel, int *srcsize, const char *src, int *tgtsize, tgt[8] = (char)((state.in_size >> 16) & 0xff); *irep = state.out_offset; + + R__lm_free(&state); + return; } From af7d8b0b50d2b66390908e3a2e2ef78c69271ec5 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 31 Jul 2026 10:40:35 +0200 Subject: [PATCH 3/4] [zip] allocate dynamically bits_internal_state in R__memcompress It used with THttpServer and causes crash with small stack. Fixes #22938 --- core/zip/src/Bits.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/core/zip/src/Bits.c b/core/zip/src/Bits.c index 0dd9672be32d5..c97b2c57cc746 100644 --- a/core/zip/src/Bits.c +++ b/core/zip/src/Bits.c @@ -299,7 +299,7 @@ ulg R__memcompress(char *tgt, ulg tgtsize, const char *src, ulg srcsize) ush flags = 0; ulg crc = 0; int method = Z_DEFLATED; - bits_internal_state state; + bits_internal_state *state = (bits_internal_state *) malloc(sizeof(bits_internal_state)); if (tgtsize <= 6L) { R__error("target buffer too small"); /* errorflag = 1; */ } #if 0 @@ -307,27 +307,27 @@ ulg R__memcompress(char *tgt, ulg tgtsize, const char *src, ulg srcsize) crc = updcrc(src, (extent) srcsize); #endif #ifdef DYN_ALLOC - state.R__window = 0; - state.R__prev = 0; + state->R__window = 0; + state->R__prev = 0; #endif /* R__read_buf = R__mem_read; */ /* assert(R__read_buf == R__mem_read); */ - state.in_buf = src; - state.in_size = (unsigned)srcsize; - state.in_offset = 0; - - state.out_buf = tgt; - state.out_size = (unsigned)tgtsize; - state.out_offset = 2 + 4; - state.R__window_size = 0L; - - R__bi_init(&state); - state.t_state = R__get_thread_tree_state(); - R__ct_init(state.t_state, &att, &method); - R__lm_init(&state,(gCompressionLevel != 0 ? gCompressionLevel : 1), &flags); - R__Deflate(&state,&(state.error_flag)); - state.R__window_size = 0L; /* was updated by lm_init() */ + state->in_buf = src; + state->in_size = (unsigned)srcsize; + state->in_offset = 0; + + state->out_buf = tgt; + state->out_size = (unsigned)tgtsize; + state->out_offset = 2 + 4; + state->R__window_size = 0L; + + R__bi_init(state); + state->t_state = R__get_thread_tree_state(); + R__ct_init(state->t_state, &att, &method); + R__lm_init(state,(gCompressionLevel != 0 ? gCompressionLevel : 1), &flags); + R__Deflate(state,&(state->error_flag)); + state->R__window_size = 0L; /* was updated by lm_init() */ /* For portability, force little-endian order on all machines: */ tgt[0] = (char)(method & 0xff); @@ -337,7 +337,12 @@ ulg R__memcompress(char *tgt, ulg tgtsize, const char *src, ulg srcsize) tgt[4] = (char)((crc >> 16) & 0xff); tgt[5] = (char)((crc >> 24) & 0xff); - return (ulg)state.out_offset; + ulg res = (ulg)state->out_offset; + + R__lm_free(state); + free(state); + + return res; } From e4bfe0b42f9789331ad77c304f62b13701de8a9a Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Mon, 3 Aug 2026 07:58:44 +0200 Subject: [PATCH 4/4] [zip] return 0 from R__memcompress when fail to allocate memory --- core/zip/src/Bits.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/zip/src/Bits.c b/core/zip/src/Bits.c index c97b2c57cc746..29516e48119cb 100644 --- a/core/zip/src/Bits.c +++ b/core/zip/src/Bits.c @@ -300,6 +300,10 @@ ulg R__memcompress(char *tgt, ulg tgtsize, const char *src, ulg srcsize) ulg crc = 0; int method = Z_DEFLATED; bits_internal_state *state = (bits_internal_state *) malloc(sizeof(bits_internal_state)); + if (!state) { + R__error("fail to allocate bits_internal_state struct"); + return 0L; + } if (tgtsize <= 6L) { R__error("target buffer too small"); /* errorflag = 1; */ } #if 0