diff --git a/arch/arm/slide_hash_armv6.c b/arch/arm/slide_hash_armv6.c index da4f51e0af..1bcdb84a0a 100644 --- a/arch/arm/slide_hash_armv6.c +++ b/arch/arm/slide_hash_armv6.c @@ -39,7 +39,7 @@ static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize } Z_INTERNAL void slide_hash_armv6(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + AssertHint(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); uint16_t wsize = (uint16_t)s->w_size; slide_hash_chain(s->head, HASH_SIZE, wsize); diff --git a/arch/arm/slide_hash_neon.c b/arch/arm/slide_hash_neon.c index f319f98790..71f905ff56 100644 --- a/arch/arm/slide_hash_neon.c +++ b/arch/arm/slide_hash_neon.c @@ -38,7 +38,7 @@ static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize } Z_INTERNAL void slide_hash_neon(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + AssertHint(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); uint16_t wsize = (uint16_t)s->w_size; slide_hash_chain(s->head, HASH_SIZE, wsize); diff --git a/arch/generic/crc32_braid_c.c b/arch/generic/crc32_braid_c.c index f80071042d..ad60cc963e 100644 --- a/arch/generic/crc32_braid_c.c +++ b/arch/generic/crc32_braid_c.c @@ -192,7 +192,7 @@ Z_INTERNAL uint32_t PREFIX(crc32_braid)(uint32_t crc, const uint8_t *buf, size_t #endif #endif words += N; - Assert(comb <= UINT32_MAX, "comb should fit in uint32_t"); + AssertHint(comb <= UINT32_MAX, "comb should fit in uint32_t"); c = (uint32_t)ZSWAPWORD(comb); /* Update the pointer to the remaining bytes to process. */ diff --git a/arch/power/slide_ppc_tpl.h b/arch/power/slide_ppc_tpl.h index 680a7f8e2a..795efe9681 100644 --- a/arch/power/slide_ppc_tpl.h +++ b/arch/power/slide_ppc_tpl.h @@ -24,7 +24,7 @@ static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize } void Z_INTERNAL SLIDE_PPC(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + AssertHint(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); uint16_t wsize = (uint16_t)s->w_size; slide_hash_chain(s->head, HASH_SIZE, wsize); diff --git a/arch/riscv/chunkset_rvv.c b/arch/riscv/chunkset_rvv.c index ee43bde2f7..dbba222b1c 100644 --- a/arch/riscv/chunkset_rvv.c +++ b/arch/riscv/chunkset_rvv.c @@ -85,7 +85,7 @@ static inline void storechunk(uint8_t *out, chunk_t *chunk) { * loadchunk and storechunk to ensure the result is correct. */ static inline uint8_t* CHUNKCOPY(uint8_t *out, uint8_t const *from, unsigned len) { - Assert(len > 0, "chunkcopy should never have a length 0"); + AssertHint(len > 0, "chunkcopy should never have a length 0"); int32_t align = ((len - 1) % sizeof(chunk_t)) + 1; memcpy(out, from, sizeof(chunk_t)); out += align; diff --git a/arch/riscv/slide_hash_rvv.c b/arch/riscv/slide_hash_rvv.c index 6f53d7a13a..91030cb9b0 100644 --- a/arch/riscv/slide_hash_rvv.c +++ b/arch/riscv/slide_hash_rvv.c @@ -23,7 +23,7 @@ static inline void slide_hash_chain(Pos *table, uint32_t entries, uint16_t wsize } Z_INTERNAL void slide_hash_rvv(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + AssertHint(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); uint16_t wsize = (uint16_t)s->w_size; slide_hash_chain(s->head, HASH_SIZE, wsize); diff --git a/arch/s390/dfltcc_deflate.c b/arch/s390/dfltcc_deflate.c index 90b4b96e9c..f45ebf6db5 100644 --- a/arch/s390/dfltcc_deflate.c +++ b/arch/s390/dfltcc_deflate.c @@ -215,8 +215,8 @@ int Z_INTERNAL PREFIX(dfltcc_deflate)(PREFIX3(streamp) strm, int flush, block_st /* DFLTCC-CMPR will write to next_out, so make sure that buffers with * higher precedence are empty. */ - Assert(state->pending == 0, "There must be no pending bytes"); - Assert(state->bi_valid < 8, "There must be less than 8 pending bits"); + AssertHint(state->pending == 0, "There must be no pending bytes"); + AssertHint(state->bi_valid < 8, "There must be less than 8 pending bits"); param->sbb = (unsigned int)state->bi_valid; if (param->sbb > 0) *strm->next_out = (unsigned char)state->bi_buf; diff --git a/arch/x86/slide_hash_avx2.c b/arch/x86/slide_hash_avx2.c index 8533473234..d188f18ab8 100644 --- a/arch/x86/slide_hash_avx2.c +++ b/arch/x86/slide_hash_avx2.c @@ -31,7 +31,7 @@ static inline void slide_hash_chain(Pos *table, uint32_t entries, const __m256i } Z_INTERNAL void slide_hash_avx2(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + AssertHint(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); uint16_t wsize = (uint16_t)s->w_size; const __m256i ymm_wsize = _mm256_set1_epi16((short)wsize); diff --git a/arch/x86/slide_hash_sse2.c b/arch/x86/slide_hash_sse2.c index 6900a59d15..3b39d08508 100644 --- a/arch/x86/slide_hash_sse2.c +++ b/arch/x86/slide_hash_sse2.c @@ -52,7 +52,7 @@ static inline void slide_hash_chain(Pos *table0, Pos *table1, uint32_t entries0, } Z_INTERNAL void slide_hash_sse2(deflate_state *s) { - Assert(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); + AssertHint(s->w_size <= UINT16_MAX, "w_size should fit in uint16_t"); uint16_t wsize = (uint16_t)s->w_size; const __m128i xmm_wsize = _mm_set1_epi16((short)wsize); diff --git a/chunkset_tpl.h b/chunkset_tpl.h index 383b4d8f84..9551f9d5c4 100644 --- a/chunkset_tpl.h +++ b/chunkset_tpl.h @@ -22,7 +22,7 @@ Z_INTERNAL uint32_t CHUNKSIZE(void) { reliable. */ #ifndef HAVE_CHUNKCOPY static inline uint8_t* CHUNKCOPY(uint8_t *out, uint8_t const *from, unsigned len) { - Assert(len > 0, "chunkcopy should never have a length 0"); + AssertHint(len > 0, "chunkcopy should never have a length 0"); chunk_t chunk; int32_t align = ((len - 1) % sizeof(chunk_t)) + 1; loadchunk(from, &chunk); @@ -112,7 +112,7 @@ static inline uint8_t* HALFCHUNKCOPY(uint8_t *out, uint8_t const *from, unsigned static inline uint8_t* CHUNKMEMSET(uint8_t *out, uint8_t *from, unsigned len) { /* Debug performance related issues when len < sizeof(uint64_t): Assert(len >= sizeof(uint64_t), "chunkmemset should be called on larger chunks"); */ - Assert(from != out, "chunkmemset cannot have a distance 0"); + AssertHint(from != out, "chunkmemset cannot have a distance 0"); chunk_t chunk_load; uint32_t chunk_mod = 0; diff --git a/deflate.c b/deflate.c index 630cce2553..3f661774b5 100644 --- a/deflate.c +++ b/deflate.c @@ -1106,7 +1106,7 @@ int32_t Z_EXPORT PREFIX(deflate)(PREFIX3(stream) *strm, int32_t flush) { if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ if (s->pending == 0) { - Assert(s->bi_valid == 0, "bi_buf not flushed"); + AssertHint(s->bi_valid == 0, "bi_buf not flushed"); return Z_STREAM_END; } return Z_OK; @@ -1274,7 +1274,7 @@ void Z_INTERNAL PREFIX(fill_window)(deflate_state *s) { unsigned int more; /* Amount of free space at the end of the window. */ unsigned int wsize = s->w_size; - Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + AssertHint(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); do { more = s->window_size - s->lookahead - s->strstart; @@ -1311,7 +1311,7 @@ void Z_INTERNAL PREFIX(fill_window)(deflate_state *s) { * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ - Assert(more >= 2, "more < 2"); + AssertHint(more >= 2, "more < 2"); n = PREFIX(read_buf)(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; diff --git a/deflate_fast.c b/deflate_fast.c index e682697d5c..bfb7d39996 100644 --- a/deflate_fast.c +++ b/deflate_fast.c @@ -58,8 +58,8 @@ Z_INTERNAL block_state deflate_fast(deflate_state *s, int flush) { } if (match_len >= WANT_MIN_MATCH) { - Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); - Assert(s->match_start <= UINT16_MAX, "match_start should fit in uint16_t"); + AssertHint(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); + AssertHint(s->match_start <= UINT16_MAX, "match_start should fit in uint16_t"); check_match(s, (Pos)s->strstart, (Pos)s->match_start, match_len); bflush = zng_tr_tally_dist(s, s->strstart - s->match_start, match_len - STD_MIN_MATCH); diff --git a/deflate_p.h b/deflate_p.h index abcc8b1c7c..9e1ac182fe 100644 --- a/deflate_p.h +++ b/deflate_p.h @@ -70,7 +70,6 @@ static inline int zng_tr_tally_lit(deflate_state *s, unsigned char c) { #endif s->dyn_ltree[c].Freq++; Tracevv((stderr, "%c", c)); - Assert(c <= (STD_MAX_MATCH-STD_MIN_MATCH), "zng_tr_tally: bad literal"); return (s->sym_next == s->sym_end); } @@ -78,8 +77,8 @@ static inline int zng_tr_tally_dist(deflate_state* s, uint32_t dist, uint32_t le /* dist: distance of matched string */ /* len: match length-STD_MIN_MATCH */ #ifdef LIT_MEM - Assert(dist <= UINT16_MAX, "dist should fit in uint16_t"); - Assert(len <= UINT8_MAX, "len should fit in uint8_t"); + AssertHint(dist <= UINT16_MAX, "dist should fit in uint16_t"); + AssertHint(len <= UINT8_MAX, "len should fit in uint8_t"); s->d_buf[s->sym_next] = (uint16_t)dist; s->l_buf[s->sym_next++] = (uint8_t)len; #else @@ -89,7 +88,7 @@ static inline int zng_tr_tally_dist(deflate_state* s, uint32_t dist, uint32_t le #endif s->matches++; dist--; - Assert(dist < MAX_DIST(s) && (uint16_t)d_code(dist) < (uint16_t)D_CODES, + AssertHint(dist < MAX_DIST(s) && (uint16_t)d_code(dist) < (uint16_t)D_CODES, "zng_tr_tally: bad match"); s->dyn_ltree[zng_length_code[len] + LITERALS + 1].Freq++; diff --git a/deflate_quick.c b/deflate_quick.c index d5fd986d7a..03f040286e 100644 --- a/deflate_quick.c +++ b/deflate_quick.c @@ -102,7 +102,7 @@ Z_INTERNAL block_state deflate_quick(deflate_state *s, int flush) { if (UNLIKELY(match_len > STD_MAX_MATCH)) match_len = STD_MAX_MATCH; - Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); + AssertHint(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); check_match(s, (Pos)s->strstart, hash_head, match_len); zng_tr_emit_dist(s, static_ltree, static_dtree, match_len - STD_MIN_MATCH, (uint32_t)dist); diff --git a/deflate_rle.c b/deflate_rle.c index 9e39810483..c6c3d251f0 100644 --- a/deflate_rle.c +++ b/deflate_rle.c @@ -56,7 +56,7 @@ Z_INTERNAL block_state deflate_rle(deflate_state *s, int flush) { /* Emit match if have run of STD_MIN_MATCH or longer, else emit literal */ if (match_len >= STD_MIN_MATCH) { - Assert(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); + AssertHint(s->strstart <= UINT16_MAX, "strstart should fit in uint16_t"); check_match(s, (Pos)s->strstart, (Pos)(s->strstart - 1), match_len); bflush = zng_tr_tally_dist(s, 1, match_len - STD_MIN_MATCH); diff --git a/deflate_slow.c b/deflate_slow.c index 4165eea2af..ef1896c823 100644 --- a/deflate_slow.c +++ b/deflate_slow.c @@ -78,7 +78,7 @@ Z_INTERNAL block_state deflate_slow(deflate_state *s, int flush) { unsigned int max_insert = s->strstart + s->lookahead - STD_MIN_MATCH; /* Do not insert strings in hash table beyond this. */ - Assert((s->strstart-1) <= UINT16_MAX, "strstart-1 should fit in uint16_t"); + AssertHint((s->strstart-1) <= UINT16_MAX, "strstart-1 should fit in uint16_t"); check_match(s, (Pos)(s->strstart - 1), s->prev_match, s->prev_length); bflush = zng_tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - STD_MIN_MATCH); diff --git a/fallback_builtins.h b/fallback_builtins.h index 8303508fa1..b9808f3f70 100644 --- a/fallback_builtins.h +++ b/fallback_builtins.h @@ -13,7 +13,7 @@ * Performance tzcnt/bsf is identical on Intel cpu, tzcnt is faster than bsf on AMD cpu. */ static __forceinline int __builtin_ctz(unsigned int value) { - Assert(value != 0, "Invalid input value: 0"); + AssertHint(value != 0, "Invalid input value: 0"); # if defined(X86_FEATURES) && !(_MSC_VER < 1700) return (int)_tzcnt_u32(value); # else @@ -29,7 +29,7 @@ static __forceinline int __builtin_ctz(unsigned int value) { * Because of that assumption trailing_zero is not initialized and the return value is not checked. */ static __forceinline int __builtin_ctzll(unsigned long long value) { - Assert(value != 0, "Invalid input value: 0"); + AssertHint(value != 0, "Invalid input value: 0"); # if defined(X86_FEATURES) && !(_MSC_VER < 1700) return (int)_tzcnt_u64(value); # else diff --git a/inffast_tpl.h b/inffast_tpl.h index 2ec865dbff..564ef6bd03 100644 --- a/inffast_tpl.h +++ b/inffast_tpl.h @@ -115,8 +115,15 @@ void Z_INTERNAL INFLATE_FAST(PREFIX3(stream) *strm, uint32_t start) { unsigned dist; /* match distance */ unsigned extra_safe; /* copy chunks safely in all cases */ - /* copy state to local variables */ state = (struct inflate_state *)strm->state; + + Assume(state->mode == LEN); + Assume(state->bits < 8); + Assume(strm->avail_in >= INFLATE_FAST_MIN_HAVE); + Assume(strm->avail_out >= INFLATE_FAST_MIN_LEFT); + Assume(start >= strm->avail_out); + + /* copy state to local variables */ in = strm->next_in; last = in + (strm->avail_in - (INFLATE_FAST_MIN_HAVE - 1)); out = strm->next_out; @@ -311,7 +318,7 @@ void Z_INTERNAL INFLATE_FAST(PREFIX3(stream) *strm, uint32_t start) { strm->avail_out = (unsigned)(out < end ? (INFLATE_FAST_MIN_LEFT - 1) + (end - out) : (INFLATE_FAST_MIN_LEFT - 1) - (out - end)); - Assert(bits <= 32, "Remaining bits greater than 32"); + AssertHint(bits <= 32, "Remaining bits greater than 32"); state->hold = (uint32_t)hold; state->bits = bits; return; diff --git a/match_tpl.h b/match_tpl.h index 47e9aed9f5..94f69547c6 100644 --- a/match_tpl.h +++ b/match_tpl.h @@ -115,7 +115,7 @@ Z_INTERNAL uint32_t LONGEST_MATCH(deflate_state *const s, Pos cur_match) { #else early_exit = s->level < EARLY_EXIT_TRIGGER_LEVEL; #endif - Assert((unsigned long)strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead"); + AssertHint((unsigned long)strstart <= s->window_size - MIN_LOOKAHEAD, "need lookahead"); for (;;) { if (cur_match >= strstart) break; diff --git a/trees.c b/trees.c index 9f2f49137f..7aa3b717b1 100644 --- a/trees.c +++ b/trees.c @@ -80,6 +80,7 @@ static int detect_data_type (deflate_state *s); * Initialize the tree data structures for a new zlib stream. */ void Z_INTERNAL zng_tr_init(deflate_state *s) { + Assume(s != NULL); s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; @@ -104,6 +105,7 @@ void Z_INTERNAL zng_tr_init(deflate_state *s) { * Initialize a new block. */ static void init_block(deflate_state *s) { + Assume(s != NULL); int n; /* iterates over tree elements */ /* Initialize the trees. */ @@ -151,6 +153,7 @@ static void init_block(deflate_state *s) { static void pqdownheap(deflate_state *s, ct_data *tree, int k) { /* tree: the tree to restore */ /* k: node to move down */ + Assume(s != NULL && tree != NULL); int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { @@ -184,6 +187,7 @@ static void pqdownheap(deflate_state *s, ct_data *tree, int k) { */ static void gen_bitlen(deflate_state *s, tree_desc *desc) { /* desc: the tree descriptor */ + Assume(s != NULL && desc != NULL); ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; @@ -321,6 +325,7 @@ Z_INTERNAL void gen_codes(ct_data *tree, int max_code, uint16_t *bl_count) { */ static void build_tree(deflate_state *s, tree_desc *desc) { /* desc: the tree descriptor */ + Assume(s != NULL && desc != NULL); ct_data *tree = desc->dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; @@ -411,6 +416,7 @@ static void build_tree(deflate_state *s, tree_desc *desc) { static void scan_tree(deflate_state *s, ct_data *tree, int max_code) { /* tree: the tree to be scanned */ /* max_code: and its largest code of non zero frequency */ + Assume(s != NULL && tree != NULL); int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -459,6 +465,8 @@ static void scan_tree(deflate_state *s, ct_data *tree, int max_code) { static void send_tree(deflate_state *s, ct_data *tree, int max_code) { /* tree: the tree to be scanned */ /* max_code and its largest code of non zero frequency */ + Assume(s != NULL && tree != NULL); + Assume(s->bi_valid <= BIT_BUF_SIZE); int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -490,7 +498,7 @@ static void send_tree(deflate_state *s, ct_data *tree, int max_code) { send_code(s, curlen, s->bl_tree, bi_buf, bi_valid); count--; } - Assert(count >= 3 && count <= 6, " 3_6?"); + AssertHint(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree, bi_buf, bi_valid); send_bits(s, count-3, 2, bi_buf, bi_valid); @@ -523,6 +531,7 @@ static void send_tree(deflate_state *s, ct_data *tree, int max_code) { * bl_order of the last bit length code to send. */ static int build_bl_tree(deflate_state *s) { + Assume(s != NULL); int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ @@ -556,10 +565,12 @@ static int build_bl_tree(deflate_state *s) { * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ static void send_all_trees(deflate_state *s, int lcodes, int dcodes, int blcodes) { + Assume(s != NULL); + Assume(s->bi_valid <= BIT_BUF_SIZE); int rank; /* index in bl_order */ - Assert(lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert(lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); + AssertHint(lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + AssertHint(lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); // Temp local variables uint32_t bi_valid = s->bi_valid; @@ -593,6 +604,8 @@ void Z_INTERNAL zng_tr_stored_block(deflate_state *s, char *buf, uint32_t stored /* buf: input block */ /* stored_len: length of input block */ /* last: one if this is the last block for a file */ + Assume(s != NULL); + zng_tr_emit_tree(s, STORED_BLOCK, last); /* send block type */ zng_tr_emit_align(s); /* align on byte boundary */ cmpr_bits_align(s); @@ -613,6 +626,7 @@ void Z_INTERNAL zng_tr_stored_block(deflate_state *s, char *buf, uint32_t stored * This takes 10 bits, of which 7 may remain in the bit buffer. */ void Z_INTERNAL zng_tr_align(deflate_state *s) { + Assume(s != NULL); zng_tr_emit_tree(s, STATIC_TREES, 0); zng_tr_emit_end_block(s, static_ltree, 0); zng_tr_flush_bits(s); @@ -626,6 +640,8 @@ void Z_INTERNAL zng_tr_flush_block(deflate_state *s, char *buf, uint32_t stored_ /* buf: input block, or NULL if too old */ /* stored_len: length of input block */ /* last: one if this is the last block for a file */ + Assume(s != NULL); + unsigned long opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ @@ -666,7 +682,7 @@ void Z_INTERNAL zng_tr_flush_block(deflate_state *s, char *buf, uint32_t stored_ opt_lenb = static_lenb; } else { - Assert(buf != NULL, "lost buf"); + AssertHint(buf != NULL, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } @@ -708,6 +724,8 @@ void Z_INTERNAL zng_tr_flush_block(deflate_state *s, char *buf, uint32_t stored_ static void compress_block(deflate_state *s, const ct_data *ltree, const ct_data *dtree) { /* ltree: literal tree */ /* dtree: distance tree */ + Assume(s != NULL && ltree != NULL && dtree != NULL); + unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned sx = 0; /* running index in symbol buffers */ @@ -754,6 +772,7 @@ static void compress_block(deflate_state *s, const ct_data *ltree, const ct_data * IN assertion: the fields Freq of dyn_ltree are set. */ static int detect_data_type(deflate_state *s) { + Assume(s != NULL); /* black_mask is the bit mask of black-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 @@ -783,6 +802,8 @@ static int detect_data_type(deflate_state *s) { * Flush the bit buffer, keeping at most 7 bits in it. */ void Z_INTERNAL zng_tr_flush_bits(deflate_state *s) { + Assume(s != NULL); + Assume(s->bi_valid <= BIT_BUF_SIZE); if (s->bi_valid >= 48) { put_uint32(s, (uint32_t)s->bi_buf); put_short(s, (uint16_t)(s->bi_buf >> 32)); @@ -811,7 +832,7 @@ void Z_INTERNAL zng_tr_flush_bits(deflate_state *s) { Z_INTERNAL uint16_t PREFIX(bi_reverse)(unsigned code, int len) { /* code: the value to invert */ /* len: its bit length */ - Assert(len >= 1 && len <= 15, "code length must be 1-15"); + AssertHint(len >= 1 && len <= 15, "code length must be 1-15"); #define bitrev8(b) \ (uint8_t)((((uint8_t)(b) * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32) return (bitrev8(code >> 8) | (uint16_t)bitrev8(code) << 8) >> (16 - len); diff --git a/trees_emit.h b/trees_emit.h index b5295ee483..eed6601f1d 100644 --- a/trees_emit.h +++ b/trees_emit.h @@ -44,6 +44,7 @@ extern Z_INTERNAL const int base_dist[D_CODES]; * otherwise the shifts will overflow. */ #define send_bits(s, t_val, t_len, bi_buf, bi_valid) {\ + Assume(bi_valid <= BIT_BUF_SIZE);\ uint64_t val = (uint64_t)t_val;\ uint32_t len = (uint32_t)t_len;\ uint32_t total_bits = bi_valid + len;\ @@ -79,6 +80,8 @@ extern Z_INTERNAL const int base_dist[D_CODES]; * Flush the bit buffer and align the output on a byte boundary */ static void bi_windup(deflate_state *s) { + Assume(s->bi_valid <= BIT_BUF_SIZE); + if (s->bi_valid > 56) { put_uint64(s, s->bi_buf); } else { @@ -104,6 +107,7 @@ static void bi_windup(deflate_state *s) { * Emit literal code */ static inline uint32_t zng_emit_lit(deflate_state *s, const ct_data *ltree, unsigned c) { + Assume(s->bi_valid <= BIT_BUF_SIZE); uint32_t bi_valid = s->bi_valid; uint64_t bi_buf = s->bi_buf; @@ -122,6 +126,7 @@ static inline uint32_t zng_emit_lit(deflate_state *s, const ct_data *ltree, unsi */ static inline uint32_t zng_emit_dist(deflate_state *s, const ct_data *ltree, const ct_data *dtree, uint32_t lc, uint32_t dist) { + Assume(s->bi_valid <= BIT_BUF_SIZE); uint32_t c, extra; uint8_t code; uint64_t match_bits; @@ -132,7 +137,7 @@ static inline uint32_t zng_emit_dist(deflate_state *s, const ct_data *ltree, con /* Send the length code, len is the match length - STD_MIN_MATCH */ code = zng_length_code[lc]; c = code+LITERALS+1; - Assert(c < L_CODES, "bad l_code"); + AssertHint(c < L_CODES, "bad l_code"); send_code_trace(s, c); match_bits = ltree[c].Code; @@ -146,7 +151,7 @@ static inline uint32_t zng_emit_dist(deflate_state *s, const ct_data *ltree, con dist--; /* dist is now the match distance - 1 */ code = d_code(dist); - Assert(code < D_CODES, "bad d_code"); + AssertHint(code < D_CODES, "bad d_code"); send_code_trace(s, code); /* Send the distance code */ @@ -171,6 +176,7 @@ static inline uint32_t zng_emit_dist(deflate_state *s, const ct_data *ltree, con * Emit end block */ static inline void zng_emit_end_block(deflate_state *s, const ct_data *ltree, const int last) { + Assume(s->bi_valid <= BIT_BUF_SIZE); uint32_t bi_valid = s->bi_valid; uint64_t bi_buf = s->bi_buf; send_code(s, END_BLOCK, ltree, bi_buf, bi_valid); @@ -200,6 +206,7 @@ static inline void zng_tr_emit_dist(deflate_state *s, const ct_data *ltree, cons * Emit start of block */ static inline void zng_tr_emit_tree(deflate_state *s, int type, const int last) { + Assume(s->bi_valid <= BIT_BUF_SIZE); uint32_t bi_valid = s->bi_valid; uint64_t bi_buf = s->bi_buf; uint32_t header_bits = (type << 1) + last; diff --git a/zbuild.h b/zbuild.h index 157ab6ffed..7e0be216cc 100644 --- a/zbuild.h +++ b/zbuild.h @@ -228,14 +228,12 @@ # include extern int Z_INTERNAL z_verbose; extern void Z_INTERNAL z_error(const char *m); -# define Assert(cond, msg) {int _cond = (cond); if (!_cond) z_error(msg);} # define Trace(x) {if (z_verbose >= 0) fprintf x;} # define Tracev(x) {if (z_verbose > 0) fprintf x;} # define Tracevv(x) {if (z_verbose > 1) fprintf x;} # define Tracec(c, x) {if (z_verbose > 0 && (c)) fprintf x;} # define Tracecv(c, x) {if (z_verbose > 1 && (c)) fprintf x;} #else -# define Assert(cond, msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) @@ -243,6 +241,44 @@ # define Tracecv(c, x) #endif +/* Prepare compiler-specific assume intrinsics */ +#if defined(__clang__) && __clang_major__ >= 4 + #define z_assume(...) do { __builtin_assume(__VA_ARGS__); } while(0) +#elif defined(__GNUC__) && __GNUC__ >= 13 + #define z_assume(...) __attribute__((__assume__(__VA_ARGS__))) +#elif defined(_MSC_VER) && _MSC_VER >= 1700 + #define z_assume(...) do { __assume(__VA_ARGS__); } while(0) +#else + #define z_assume(...) +#endif +/* + Assume - Run check in Debug builds, send hint to compiler in Release builds. + Assert - Run check in Debug builds + AssertHint - Run check in Debug builds, send hint to compiler in Release builds. + Both Assert types require a second parameter msg containing an error message. + + The Assume(cond) and AssertHint(cond,msg) macros provides hints to compiler and + static analyzers about what value range is valid for a variable, helping them + better understand and optimize for real use. + To ensure this does not hide bugs, compilation in debug mode will replace hinting + with assert checks of the hint, and will throw an error on failed checks. + + Example: + void process_buffer(char* buf, size_t len) { + Assume(len <= 1024); // Hint to compiler about maximum size + ... + } +*/ +#ifdef ZLIB_DEBUG +# define Assert(cond, msg) {int _cond = (cond); if (!_cond) z_error(msg);} +# define AssertHint(cond, msg) Assert(cond,msg) +# define Assume(cond) Assert(cond, "Value assumption failed") +#else +# define Assert(cond, msg) +# define AssertHint(cond, msg) z_assume(cond) +# define Assume(cond) z_assume(cond) +#endif + /* OPTIMAL_CMP values determine the comparison width: * 64: Best for 64-bit architectures with unaligned access * 32: Best for 32-bit architectures with unaligned access