From: Hans Kristian Rosbach Date: Fri, 4 Jul 2025 15:53:09 +0000 (+0200) Subject: Reorganize initialization and buffer allocation for gzopen/gzread/gzwrite X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2f143aa5ceb9a38aa352872c3ae3f6eccb0e883f;p=thirdparty%2Fzlib-ng.git Reorganize initialization and buffer allocation for gzopen/gzread/gzwrite --- diff --git a/gzguts.h b/gzguts.h index 14f23911..1f9adbfc 100644 --- a/gzguts.h +++ b/gzguts.h @@ -135,6 +135,10 @@ typedef gz_state *gz_statep; /* shared functions */ void Z_INTERNAL gz_error(gz_state *, int, const char *); +int Z_INTERNAL gz_buffer_alloc(gz_state *state); +void Z_INTERNAL gz_buffer_free(gz_state *state); +void Z_INTERNAL gz_state_free(gz_state *state); + #ifdef ZLIB_COMPAT unsigned Z_INTERNAL gz_intmax(void); #endif diff --git a/gzlib.c b/gzlib.c index b8a506b6..56815c20 100644 --- a/gzlib.c +++ b/gzlib.c @@ -18,9 +18,39 @@ #endif /* Local functions */ +static gzFile gz_state_init(); static void gz_reset(gz_state *); static gzFile gz_open(const void *, int, const char *); +/* Initialize struct for gzFile state */ +static gzFile gz_state_init() { + /* allocate gzFile structure to return */ + gz_state *state = (gz_state *)zng_alloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + + state->strm.zalloc = NULL; + state->strm.zfree = NULL; + state->strm.opaque = NULL; + state->strm.next_in = NULL; + + state->size = 0; + state->want = GZBUFSIZE; + state->in = NULL; + state->out = NULL; + state->direct = 0; + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + state->msg = NULL; + + return (gzFile)state; +} + +void Z_INTERNAL gz_state_free(gz_state *state) { + zng_free(state); +} + /* Reset gzip file state */ static void gz_reset(gz_state *state) { state->x.have = 0; /* no output data available */ @@ -37,6 +67,40 @@ static void gz_reset(gz_state *state) { state->strm.avail_in = 0; /* no input data yet */ } +/* Allocate in/out buffers for gzFile */ +int Z_INTERNAL gz_buffer_alloc(gz_state *state) { + int in_mult = 1, out_mult = 1; + int skip_outbuff = (state->mode == GZ_WRITE && state->direct); + + if (state->mode == GZ_WRITE) + in_mult = 2; // double imput buffer for compression (ref: gzprintf) + else if (state->mode == GZ_READ) + out_mult = 2; // double output buffer for decompression + + state->in = (unsigned char *)zng_alloc(state->want * in_mult); + /* Don't need output buffer if compressing with state->direct set */ + if ( !skip_outbuff ) { + state->out = (unsigned char *)zng_alloc(state->want * out_mult); + } + + /* Return error if memory allocation failed */ + if (state->in == NULL || (!skip_outbuff && state->out == NULL) ) { + gz_buffer_free(state); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + state->size = state->want; // mark state as initialized + + return 0; +} + +void Z_INTERNAL gz_buffer_free(gz_state *state) { + zng_free(state->out); + zng_free(state->in); + state->size = 0; +} + /* Open a gzip file either by name or file descriptor. */ static gzFile gz_open(const void *path, int fd, const char *mode) { gz_state *state; @@ -53,19 +117,12 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { if (path == NULL) return NULL; - /* allocate gzFile structure to return */ - state = (gz_state *)zng_alloc(sizeof(gz_state)); + /* Initialize gzFile state */ + state = (gz_state *)gz_state_init(); if (state == NULL) return NULL; - state->size = 0; /* no buffers allocated yet */ - state->want = GZBUFSIZE; /* requested buffer size */ - state->msg = NULL; /* no error message yet */ /* interpret mode */ - state->mode = GZ_NONE; - state->level = Z_DEFAULT_COMPRESSION; - state->strategy = Z_DEFAULT_STRATEGY; - state->direct = 0; while (*mode) { if (*mode >= '0' && *mode <= '9') { state->level = *mode - '0'; @@ -83,7 +140,7 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { break; #endif case '+': /* can't read and write at the same time */ - zng_free(state); + gz_state_free(state); return NULL; case 'b': /* ignore -- will request binary anyway */ break; @@ -121,14 +178,14 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { /* must provide an "r", "w", or "a" */ if (state->mode == GZ_NONE) { - zng_free(state); + gz_state_free(state); return NULL; } /* can't force transparent read */ if (state->mode == GZ_READ) { if (state->direct) { - zng_free(state); + gz_state_free(state); return NULL; } state->direct = 1; /* for empty file */ @@ -145,7 +202,7 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { len = strlen((const char *)path); state->path = (char *)malloc(len + 1); if (state->path == NULL) { - zng_free(state); + gz_state_free(state); return NULL; } #ifdef WIDECHAR @@ -190,7 +247,7 @@ static gzFile gz_open(const void *path, int fd, const char *mode) { open((const char *)path, oflag, 0666)); if (state->fd == -1) { free(state->path); - zng_free(state); + gz_state_free(state); return NULL; } if (state->mode == GZ_APPEND) { @@ -224,14 +281,13 @@ gzFile Z_EXPORT PREFIX4(gzopen)(const char *path, const char *mode) { /* -- see zlib.h -- */ gzFile Z_EXPORT PREFIX(gzdopen)(int fd, const char *mode) { - char *path; /* identifier for error messages */ gzFile gz; + char path[32]; /* identifier for error messages */ - if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) + if (fd == -1) return NULL; - (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); /* for debugging */ + (void)snprintf(path, 32, "", fd); /* for debugging */ gz = gz_open(path, fd, mode); - free(path); return gz; } diff --git a/gzread.c.in b/gzread.c.in index 1fc7b370..e725d54a 100644 --- a/gzread.c.in +++ b/gzread.c.in @@ -81,29 +81,15 @@ static int gz_avail(gz_state *state) { static int gz_look(gz_state *state) { PREFIX3(stream) *strm = &(state->strm); - /* allocate read buffers and inflate memory */ if (state->size == 0) { - /* allocate buffers */ - state->in = (unsigned char *)zng_alloc(state->want); - state->out = (unsigned char *)zng_alloc(state->want << 1); - if (state->in == NULL || state->out == NULL) { - zng_free(state->out); - zng_free(state->in); - gz_error(state, Z_MEM_ERROR, "out of memory"); + /* Allocate gz buffers */ + if (gz_buffer_alloc(state) != 0) { return -1; } - state->size = state->want; - - /* allocate inflate memory */ - state->strm.zalloc = NULL; - state->strm.zfree = NULL; - state->strm.opaque = NULL; - state->strm.avail_in = 0; - state->strm.next_in = NULL; + + /* Initialize inflate state */ if (PREFIX(inflateInit2)(&(state->strm), MAX_WBITS + 16) != Z_OK) { /* gunzip */ - zng_free(state->out); - zng_free(state->in); - state->size = 0; + gz_buffer_free(state); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } @@ -594,8 +580,7 @@ int Z_EXPORT PREFIX(gzclose_r)(gzFile file) { /* free memory and close file */ if (state->size) { PREFIX(inflateEnd)(&(state->strm)); - zng_free(state->out); - zng_free(state->in); + gz_buffer_free(state); } err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; gz_error(state, Z_OK, NULL); diff --git a/gzwrite.c b/gzwrite.c index 08e0ce9a..7bac0f77 100644 --- a/gzwrite.c +++ b/gzwrite.c @@ -21,43 +21,22 @@ static int gz_init(gz_state *state) { int ret; PREFIX3(stream) *strm = &(state->strm); - /* allocate input buffer (double size for gzprintf) */ - state->in = (unsigned char *)zng_alloc(state->want << 1); - if (state->in == NULL) { - gz_error(state, Z_MEM_ERROR, "out of memory"); + /* Allocate gz buffers */ + if (gz_buffer_alloc(state) != 0) return -1; - } - memset(state->in, 0, state->want << 1); - /* only need output buffer and deflate state if compressing */ + /* only need deflate state if compressing */ if (!state->direct) { - /* allocate output buffer */ - state->out = (unsigned char *)zng_alloc(state->want); - if (state->out == NULL) { - zng_free(state->in); - gz_error(state, Z_MEM_ERROR, "out of memory"); - return -1; - } - /* allocate deflate memory, set up for gzip compression */ - strm->zalloc = NULL; - strm->zfree = NULL; - strm->opaque = NULL; ret = PREFIX(deflateInit2)(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); if (ret != Z_OK) { - zng_free(state->out); - zng_free(state->in); + gz_buffer_free(state); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } strm->next_in = NULL; - } - /* mark state as initialized */ - state->size = state->want; - - /* initialize write buffer if compressing */ - if (!state->direct) { + /* initialize write buffer */ strm->avail_out = state->size; strm->next_out = state->out; state->x.next = strm->next_out; @@ -513,14 +492,13 @@ int Z_EXPORT PREFIX(gzclose_w)(gzFile file) { if (state->size) { if (!state->direct) { (void)PREFIX(deflateEnd)(&(state->strm)); - zng_free(state->out); } - zng_free(state->in); + gz_buffer_free(state); } gz_error(state, Z_OK, NULL); free(state->path); if (close(state->fd) == -1) ret = Z_ERRNO; - zng_free(state); + gz_state_free(state); return ret; } diff --git a/zutil.c b/zutil.c index 99818c3a..886e0ce5 100644 --- a/zutil.c +++ b/zutil.c @@ -109,3 +109,41 @@ void Z_INTERNAL PREFIX(zcfree)(void *opaque, void *ptr) { Z_UNUSED(opaque); zng_free(ptr); } + +/* Provide aligned allocations, only used by gz* code */ +void Z_INTERNAL *zng_alloc_aligned(unsigned size, unsigned align) { + uintptr_t return_ptr, original_ptr; + uint32_t alloc_size, align_diff; + void *ptr; + + /* Allocate enough memory for proper alignment and to store the original memory pointer */ + alloc_size = sizeof(void *) + size + align; + ptr = zng_alloc(alloc_size); + if (!ptr) + return NULL; + + /* Calculate return pointer address with space enough to store original pointer */ + align_diff = align - ((uintptr_t)ptr % align); + return_ptr = (uintptr_t)ptr + align_diff; + if (align_diff < sizeof(void *)) + return_ptr += align; + + /* Store the original pointer for free() */ + original_ptr = return_ptr - sizeof(void *); + memcpy((void *)original_ptr, &ptr, sizeof(void *)); + + /* Return properly aligned pointer in allocation */ + return (void *)return_ptr; +} + +void Z_INTERNAL zng_free_aligned(void *ptr) { + if (!ptr) + return; + + /* Calculate offset to original memory allocation pointer */ + void *original_ptr = (void *)((uintptr_t)ptr - sizeof(void *)); + void *free_ptr = *(void **)original_ptr; + + /* Free original memory allocation */ + zng_free(free_ptr); +} diff --git a/zutil.h b/zutil.h index a6284502..9017c687 100644 --- a/zutil.h +++ b/zutil.h @@ -133,6 +133,8 @@ extern z_const char * const PREFIX(z_errmsg)[10]; /* indexed by 2-zlib_error */ void Z_INTERNAL *PREFIX(zcalloc)(void *opaque, unsigned items, unsigned size); void Z_INTERNAL PREFIX(zcfree)(void *opaque, void *ptr); +void Z_INTERNAL *zng_alloc_aligned(unsigned size, unsigned align); +void Z_INTERNAL zng_free_aligned(void *ptr); typedef void *zng_calloc_func(void *opaque, unsigned items, unsigned size); typedef void zng_cfree_func(void *opaque, void *ptr);