From: Matt Suiche Date: Tue, 23 Mar 2021 16:33:34 +0000 (+0400) Subject: compression: fix lzxpress-compress X-Git-Tag: talloc-2.3.4~180 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3c2f1f03c1937b180d539ad9bb96540ce1dd957b;p=thirdparty%2Fsamba.git compression: fix lzxpress-compress Signed-off-by: Matt Suiche Reviewed-by: Joseph Sutton Reviewed-by: Douglas Bagnall --- diff --git a/lib/compression/lzxpress.c b/lib/compression/lzxpress.c index 4b2ffbda0f2..a428d0397c8 100644 --- a/lib/compression/lzxpress.c +++ b/lib/compression/lzxpress.c @@ -57,6 +57,17 @@ )) #endif +#define __CHECK_BYTES(__size, __index, __needed) do { \ + if (unlikely(__index >= __size)) { \ + return -1; \ + } else { \ + uint32_t __avail = __size - __index; \ + if (unlikely(__needed > __avail)) { \ + return -1; \ + } \ + } \ +} while(0) + ssize_t lzxpress_compress(const uint8_t *uncompressed, uint32_t uncompressed_size, uint8_t *compressed, @@ -65,7 +76,7 @@ ssize_t lzxpress_compress(const uint8_t *uncompressed, uint32_t uncompressed_pos, compressed_pos, byte_left; uint32_t max_offset, best_offset; int32_t offset; - uint32_t max_len, len, best_len; + uint32_t max_len, len, best_len, match_len; const uint8_t *str1, *str2; uint32_t indic; uint8_t *indic_pos; @@ -92,7 +103,8 @@ ssize_t lzxpress_compress(const uint8_t *uncompressed, if (uncompressed_pos > XPRESS_BLOCK_SIZE) return 0; - do { + while ((uncompressed_pos < uncompressed_size) && + (compressed_pos < max_compressed_size)) { bool found = false; max_offset = uncompressed_pos; @@ -109,7 +121,7 @@ ssize_t lzxpress_compress(const uint8_t *uncompressed, str2 = &str1[-offset]; /* maximum len we can encode into metadata */ - max_len = MIN((255 + 15 + 7 + 3), byte_left); + max_len = MIN(0x1FFF, byte_left); for (len = 0; (len < max_len) && (str1[len] == str2[len]); len++); @@ -124,112 +136,128 @@ ssize_t lzxpress_compress(const uint8_t *uncompressed, } } - if (found) { + if (!found) { + __CHECK_BYTES(uncompressed_size, uncompressed_pos, sizeof(uint8_t)); + __CHECK_BYTES(max_compressed_size, compressed_pos, sizeof(uint8_t)); + compressed[compressed_pos++] = uncompressed[uncompressed_pos++]; + byte_left--; + + indic <<= 1; + indic_bit += 1; + + if (indic_bit == 32) { + SIVAL(indic_pos, 0, indic); + indic_bit = 0; + __CHECK_BYTES(max_compressed_size, compressed_pos, sizeof(uint32_t)); + indic_pos = &compressed[compressed_pos]; + compressed_pos += sizeof(uint32_t); + } + } else { metadata_size = 0; + match_len = best_len; + __CHECK_BYTES(max_compressed_size, compressed_pos, sizeof(uint16_t)); dest = (uint16_t *)&compressed[compressed_pos]; - if (best_len < 10) { + match_len -= 3; + best_offset -= 1; + + if (match_len < 7) { /* Classical meta-data */ - metadata = (uint16_t)(((best_offset - 1) << 3) | (best_len - 3)); + __CHECK_BYTES(max_compressed_size, compressed_pos, sizeof(uint16_t)); + metadata = (uint16_t)((best_offset << 3) + match_len); SSVAL(dest, metadata_size / sizeof(uint16_t), metadata); metadata_size += sizeof(uint16_t); } else { - metadata = (uint16_t)(((best_offset - 1) << 3) | 7); + bool has_extra = false; + __CHECK_BYTES(max_compressed_size, compressed_pos, sizeof(uint16_t)); + metadata = (uint16_t)(best_offset << 3) | 7; SSVAL(dest, metadata_size / sizeof(uint16_t), metadata); - metadata_size = sizeof(uint16_t); + metadata_size += sizeof(uint16_t); + + match_len -= 7; - if (best_len < (15 + 7 + 3)) { - /* Shared byte */ - if (!nibble_index) { - compressed[compressed_pos + metadata_size] = (best_len - (3 + 7)) & 0xF; + if (!nibble_index) { + nibble_index = compressed_pos; + if (match_len < 15) { + __CHECK_BYTES(max_compressed_size, compressed_pos + metadata_size, sizeof(uint8_t)); + compressed[compressed_pos + metadata_size] = match_len & 0xFF;; metadata_size += sizeof(uint8_t); } else { - compressed[nibble_index] &= 0xF; - compressed[nibble_index] |= (best_len - (3 + 7)) * 16; - } - } else if (best_len < (3 + 7 + 15 + 255)) { - /* Shared byte */ - if (!nibble_index) { + __CHECK_BYTES(max_compressed_size, compressed_pos + metadata_size, sizeof(uint8_t)); compressed[compressed_pos + metadata_size] = 15; metadata_size += sizeof(uint8_t); - } else { - compressed[nibble_index] &= 0xF; - compressed[nibble_index] |= (15 * 16); + has_extra = true; } - - /* Additional best_len */ - compressed[compressed_pos + metadata_size] = (best_len - (3 + 7 + 15)) & 0xFF; - metadata_size += sizeof(uint8_t); } else { - /* Shared byte */ - if (!nibble_index) { - compressed[compressed_pos + metadata_size] |= 15; - metadata_size += sizeof(uint8_t); + if (match_len < 15) { + // compressed[nibble_index] &= 0xF; + __CHECK_BYTES(max_compressed_size, nibble_index, sizeof(uint8_t)); + compressed[nibble_index] |= (match_len << 4) & 0xFF; + nibble_index = 0; } else { - compressed[nibble_index] |= 15 << 4; + __CHECK_BYTES(max_compressed_size, nibble_index, sizeof(uint8_t)); + compressed[nibble_index] |= (15 << 4); + nibble_index = 0; + has_extra = true; } + } - /* Additional best_len */ - compressed[compressed_pos + metadata_size] = 255; + if (has_extra) { + match_len -= 15; - metadata_size += sizeof(uint8_t); + if (match_len < 255) { + __CHECK_BYTES(max_compressed_size, compressed_pos + metadata_size, sizeof(uint8_t)); + compressed[compressed_pos + metadata_size] = match_len & 0xFF; + metadata_size += sizeof(uint8_t); + } else { + /* Additional match_len */ + __CHECK_BYTES(max_compressed_size, compressed_pos + metadata_size, sizeof(uint8_t)); + compressed[compressed_pos + metadata_size] = 255; + metadata_size += sizeof(uint8_t); - compressed[compressed_pos + metadata_size] = (best_len - 3) & 0xFF; - compressed[compressed_pos + metadata_size + 1] = ((best_len - 3) >> 8) & 0xFF; - metadata_size += sizeof(uint16_t); + match_len += 7 + 15; + + if (match_len < (1 << 16)) { + __CHECK_BYTES(max_compressed_size, compressed_pos + metadata_size, sizeof(uint16_t)); + compressed[compressed_pos + metadata_size] = match_len & 0xFF; + compressed[compressed_pos + metadata_size + 1] = (match_len >> 8); + metadata_size += sizeof(uint16_t); + } else { + __CHECK_BYTES(max_compressed_size, compressed_pos + metadata_size, sizeof(uint16_t) + sizeof(uint32_t)); + compressed[compressed_pos + metadata_size] = 0; + compressed[compressed_pos + metadata_size + 1] = 0; + metadata_size += sizeof(uint16_t); + + compressed[compressed_pos + metadata_size] = match_len & 0xFF; + compressed[compressed_pos + metadata_size + 1] = (match_len >> 8) & 0xFF; + compressed[compressed_pos + metadata_size + 2] = (match_len >> 16) & 0xFF; + compressed[compressed_pos + metadata_size + 3] = (match_len >> 24) & 0xFF; + metadata_size += sizeof(uint32_t); + } + } } } - indic |= 1U << (32 - ((indic_bit % 32) + 1)); + indic = (indic << 1) | 1; + indic_bit += 1; - if (best_len > 9) { - if (nibble_index == 0) { - nibble_index = compressed_pos + sizeof(uint16_t); - } else { - nibble_index = 0; - } + if (indic_bit == 32) { + SIVAL(indic_pos, 0, indic); + indic_bit = 0; + indic_pos = &compressed[compressed_pos]; + compressed_pos += sizeof(uint32_t); } compressed_pos += metadata_size; uncompressed_pos += best_len; byte_left -= best_len; - } else { - compressed[compressed_pos++] = uncompressed[uncompressed_pos++]; - byte_left--; - } - indic_bit++; - - if ((indic_bit - 1) % 32 > (indic_bit % 32)) { - SIVAL(indic_pos, 0, indic); - indic = 0; - indic_pos = &compressed[compressed_pos]; - compressed_pos += sizeof(uint32_t); - } - } while (byte_left > 3); - - do { - compressed[compressed_pos] = uncompressed[uncompressed_pos]; - indic_bit++; - - uncompressed_pos++; - compressed_pos++; - if (((indic_bit - 1) % 32) > (indic_bit % 32)){ - SIVAL(indic_pos, 0, indic); - indic = 0; - indic_pos = &compressed[compressed_pos]; - compressed_pos += sizeof(uint32_t); } - } while (uncompressed_pos < uncompressed_size); - - if ((indic_bit % 32) > 0) { - for (; (indic_bit % 32) != 0; indic_bit++) - indic |= 1U << (32 - ((indic_bit % 32) + 1)); - - SIVAL(compressed, compressed_pos, 0); - SIVAL(indic_pos, 0, indic); - compressed_pos += sizeof(uint32_t); } + indic <<= 32 - indic_bit; + indic |= (1 << (32 - indic_bit)) - 1; + SIVAL(indic_pos, 0, indic); + return compressed_pos; } @@ -253,16 +281,6 @@ ssize_t lzxpress_decompress(const uint8_t *input, offset = 0; nibble_index = 0; -#define __CHECK_BYTES(__size, __index, __needed) do { \ - if (unlikely(__index >= __size)) { \ - return -1; \ - } else { \ - uint32_t __avail = __size - __index; \ - if (unlikely(__needed > __avail)) { \ - return -1; \ - } \ - } \ -} while(0) #define CHECK_INPUT_BYTES(__needed) \ __CHECK_BYTES(input_size, input_index, __needed) #define CHECK_OUTPUT_BYTES(__needed) \ diff --git a/selftest/knownfail.d/lzxpress b/selftest/knownfail.d/lzxpress deleted file mode 100644 index bdfe64dce8a..00000000000 --- a/selftest/knownfail.d/lzxpress +++ /dev/null @@ -1,3 +0,0 @@ -samba4.local.compression.lzxpress -samba4.local.compression.lzxpress2 -samba4.local.compression.lzxpress3