if (strm == NULL || strm->zalloc == NULL || strm->zfree == NULL)
return 1;
state = (struct inflate_state *)strm->state;
- if (state == NULL || state->strm != strm || state->mode < HEAD || state->mode > SYNC)
+ if (state == NULL || state->alloc_bufs == NULL || state->strm != strm || state->mode < HEAD || state->mode > SYNC)
return 1;
return 0;
}
#endif
}
- /* set number of window bits, free window if different */
+ /* set number of window bits */
if (windowBits && (windowBits < MIN_WBITS || windowBits > MAX_WBITS))
return Z_STREAM_ERROR;
- if (state->window != NULL && state->wbits != (unsigned)windowBits) {
- ZFREE_WINDOW(strm, state->window);
- state->window = NULL;
- }
/* update state and reset the rest of it */
state->wrap = wrap;
return PREFIX(inflateReset)(strm);
}
-/* This function is hidden in ZLIB_COMPAT builds. */
+#ifdef INF_ALLOC_DEBUG
+# include <stdio.h>
+# define LOGSZ(name,size) fprintf(stderr, "%s is %d bytes\n", name, size)
+# define LOGSZP(name,size,loc,pad) fprintf(stderr, "%s is %d bytes, offset %d, padded %d\n", name, size, loc, pad)
+# define LOGSZPL(name,size,loc,pad) fprintf(stderr, "%s is %d bytes, offset %ld, padded %d\n", name, size, loc, pad)
+#else
+# define LOGSZ(name,size)
+# define LOGSZP(name,size,loc,pad)
+# define LOGSZPL(name,size,loc,pad)
+#endif
+
+/* ===========================================================================
+ * Allocate a big buffer and divide it up into the various buffers inflate needs.
+ * Handles alignment of allocated buffer and alignment of individual buffers.
+ */
+Z_INTERNAL inflate_allocs* alloc_inflate(PREFIX3(stream) *strm) {
+ int curr_size = 0;
+
+ /* Define sizes */
+ int window_size = INFLATE_ADJUST_WINDOW_SIZE((1 << MAX_WBITS) + 64); /* 64B padding for chunksize */
+ int state_size = sizeof(inflate_state);
+ int alloc_size = sizeof(inflate_allocs);
+
+ /* Calculate relative buffer positions and paddings */
+ LOGSZP("window", window_size, PAD_WINDOW(curr_size), PADSZ(curr_size,WINDOW_PAD_SIZE));
+ int window_pos = PAD_WINDOW(curr_size);
+ curr_size = window_pos + window_size;
+
+ LOGSZP("state", state_size, PAD_64(curr_size), PADSZ(curr_size,64));
+ int state_pos = PAD_64(curr_size);
+ curr_size = state_pos + state_size;
+
+ LOGSZP("alloc", alloc_size, PAD_16(curr_size), PADSZ(curr_size,16));
+ int alloc_pos = PAD_16(curr_size);
+ curr_size = alloc_pos + alloc_size;
+
+ /* Add 64-1 or 4096-1 to allow window alignment, and round size of buffer up to multiple of 64 */
+ int total_size = PAD_64(curr_size + (WINDOW_PAD_SIZE - 1));
+
+ /* Allocate buffer, align to 64-byte cacheline, and zerofill the resulting buffer */
+ char *original_buf = strm->zalloc(strm->opaque, 1, total_size);
+ if (original_buf == NULL)
+ return NULL;
+
+ char *buff = (char *)HINT_ALIGNED_WINDOW((char *)PAD_WINDOW(original_buf));
+ LOGSZPL("Buffer alloc", total_size, PADSZ((uintptr_t)original_buf,WINDOW_PAD_SIZE), PADSZ(curr_size,WINDOW_PAD_SIZE));
+
+ /* Initialize alloc_bufs */
+ inflate_allocs *alloc_bufs = (struct inflate_allocs_s *)(buff + alloc_pos);
+ alloc_bufs->buf_start = (char *)original_buf;
+ alloc_bufs->zfree = strm->zfree;
+
+ alloc_bufs->window = (unsigned char *)HINT_ALIGNED_WINDOW((buff + window_pos));
+ alloc_bufs->state = (inflate_state *)HINT_ALIGNED_64((buff + state_pos));
+
+#ifdef Z_MEMORY_SANITIZER
+ /* This is _not_ to subvert the memory sanitizer but to instead unposion some
+ data we willingly and purposefully load uninitialized into vector registers
+ in order to safely read the last < chunksize bytes of the window. */
+ __msan_unpoison(alloc_bufs->window + window_size, 64);
+#endif
+
+ return alloc_bufs;
+}
+
+/* ===========================================================================
+ * Free all allocated inflate buffers
+ */
+Z_INTERNAL void free_inflate(PREFIX3(stream) *strm) {
+ struct inflate_state *state = (struct inflate_state *)strm->state;
+
+ if (state->alloc_bufs != NULL) {
+ inflate_allocs *alloc_bufs = state->alloc_bufs;
+ alloc_bufs->zfree(strm->opaque, alloc_bufs->buf_start);
+ strm->state = NULL;
+ }
+}
+
+/* ===========================================================================
+ * Initialize inflate state and buffers.
+ * This function is hidden in ZLIB_COMPAT builds.
+ */
int32_t ZNG_CONDEXPORT PREFIX(inflateInit2)(PREFIX3(stream) *strm, int32_t windowBits) {
int32_t ret;
struct inflate_state *state;
}
if (strm->zfree == NULL)
strm->zfree = PREFIX(zcfree);
- state = ZALLOC(strm, 1, sizeof(struct inflate_state));
- if (state == NULL)
+
+ inflate_allocs *alloc_bufs = alloc_inflate(strm);
+ if (alloc_bufs == NULL)
return Z_MEM_ERROR;
+
+ state = alloc_bufs->state;
+ state->window = alloc_bufs->window;
+ state->alloc_bufs = alloc_bufs;
Tracev((stderr, "inflate: allocated\n"));
+
strm->state = (struct internal_state *)state;
state->strm = strm;
- state->window = NULL;
state->mode = HEAD; /* to pass state test in inflateReset2() */
state->chunksize = FUNCTABLE_CALL(chunksize)();
ret = PREFIX(inflateReset2)(strm, windowBits);
if (ret != Z_OK) {
- ZFREE(strm, state);
- strm->state = NULL;
+ free_inflate(strm);
}
return ret;
}
}
int Z_INTERNAL PREFIX(inflate_ensure_window)(struct inflate_state *state) {
- /* if it hasn't been done already, allocate space for the window */
- if (state->window == NULL) {
- unsigned wsize = 1U << state->wbits;
- state->window = (unsigned char *)ZALLOC_WINDOW(state->strm, wsize + state->chunksize, sizeof(unsigned char));
- if (state->window == NULL)
- return Z_MEM_ERROR;
-#ifdef Z_MEMORY_SANITIZER
- /* This is _not_ to subvert the memory sanitizer but to instead unposion some
- data we willingly and purposefully load uninitialized into vector registers
- in order to safely read the last < chunksize bytes of the window. */
- __msan_unpoison(state->window + wsize, state->chunksize);
-#endif
- }
-
/* if window not in use yet, initialize */
if (state->wsize == 0) {
state->wsize = 1U << state->wbits;
}
int32_t Z_EXPORT PREFIX(inflateEnd)(PREFIX3(stream) *strm) {
- struct inflate_state *state;
if (inflateStateCheck(strm))
return Z_STREAM_ERROR;
- state = (struct inflate_state *)strm->state;
- if (state->window != NULL)
- ZFREE_WINDOW(strm, state->window);
- ZFREE(strm, strm->state);
- strm->state = NULL;
+
+ /* Free allocated buffers */
+ free_inflate(strm);
+
Tracev((stderr, "inflate: end\n"));
return Z_OK;
}
return Z_STREAM_ERROR;
state = (struct inflate_state *)source->state;
+ /* copy stream */
+ memcpy((void *)dest, (void *)source, sizeof(PREFIX3(stream)));
+
/* allocate space */
- copy = ZALLOC(source, 1, sizeof(struct inflate_state));
- if (copy == NULL)
+ inflate_allocs *alloc_bufs = alloc_inflate(dest);
+ if (alloc_bufs == NULL)
return Z_MEM_ERROR;
+ copy = alloc_bufs->state;
/* copy state */
- memcpy((void *)dest, (void *)source, sizeof(PREFIX3(stream)));
memcpy(copy, state, sizeof(struct inflate_state));
copy->strm = dest;
if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) {
copy->distcode = copy->codes + (state->distcode - state->codes);
}
copy->next = copy->codes + (state->next - state->codes);
+ copy->window = alloc_bufs->window;
+ copy->alloc_bufs = alloc_bufs;
/* window */
- copy->window = NULL;
- if (state->window != NULL) {
- if (PREFIX(inflate_ensure_window)(copy)) {
- ZFREE(source, copy);
- return Z_MEM_ERROR;
- }
- ZCOPY_WINDOW(copy->window, state->window, (size_t)state->wsize);
- }
+ memcpy(copy->window, state->window, INFLATE_ADJUST_WINDOW_SIZE((size_t)state->wsize));
dest->state = (struct internal_state *)copy;
return Z_OK;