Introduce a BROTLI_BUILD_PORTABLE macro to disable potentially dangerous optimizations.

This commit is contained in:
Zoltan Szabadka 2015-09-25 17:57:19 +02:00
parent 85301238ea
commit e44caf9835
3 changed files with 49 additions and 31 deletions

View File

@ -36,15 +36,19 @@ void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input) {
} }
int BrotliWarmupBitReader(BrotliBitReader* const br) { int BrotliWarmupBitReader(BrotliBitReader* const br) {
if (br->bit_pos_ == (sizeof(br->val_) << 3)) { size_t aligned_read_mask = (sizeof(br->val_) >> 1) - 1;
/* Fixing alignment after unaligned BrotliFillWindow would result accumulator
overflow. If unalignment is caused by BrotliSafeReadBits, then there is
enough space in accumulator to fix aligment. */
if (!BROTLI_ALIGNED_READ) {
aligned_read_mask = 0;
}
while (br->bit_pos_ == (sizeof(br->val_) << 3) ||
(((size_t)br->next_in) & aligned_read_mask) != 0) {
if (!br->avail_in) { if (!br->avail_in) {
return 0; return 0;
} }
br->bit_pos_ -= 8; BrotliPullByte(br);
br->val_ = *br->next_in;
br->val_ <<= br->bit_pos_;
br->next_in++;
br->avail_in--;
} }
return 1; return 1;
} }

View File

@ -59,7 +59,9 @@ typedef struct {
void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input); void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input);
/* Ensures that accumulator is not empty. May consume one byte of input. /* Ensures that accumulator is not empty. May consume one byte of input.
Returns 0 if data is required but there is no input available. */ Returns 0 if data is required but there is no input available.
For BROTLI_BUILD_PORTABLE this function also prepares bit reader for aligned
reading. */
int BrotliWarmupBitReader(BrotliBitReader* const br); int BrotliWarmupBitReader(BrotliBitReader* const br);
/* Pulls data from the input to the the read buffer. /* Pulls data from the input to the the read buffer.
@ -129,11 +131,12 @@ static BROTLI_INLINE int BrotliCheckInputAmount(
/* Guarantees that there are at least n_bits + 1 bits in accumulator. /* Guarantees that there are at least n_bits + 1 bits in accumulator.
Precondition: accumulator contains at least 1 bit. Precondition: accumulator contains at least 1 bit.
n_bits should be in the range [1..24] */ n_bits should be in the range [1..24] for regular build. For portable
non-64-bit little endian build only 16 bits are safe to request. */
static BROTLI_INLINE void BrotliFillBitWindow( static BROTLI_INLINE void BrotliFillBitWindow(
BrotliBitReader* const br, int n_bits) { BrotliBitReader* const br, int n_bits) {
#if (BROTLI_64_BITS_LITTLE_ENDIAN) #if (BROTLI_64_BITS_LITTLE_ENDIAN)
if (IS_CONSTANT(n_bits) && n_bits <= 8) { if (!BROTLI_ALIGNED_READ && IS_CONSTANT(n_bits) && (n_bits <= 8)) {
if (br->bit_pos_ >= 56) { if (br->bit_pos_ >= 56) {
br->val_ >>= 56; br->val_ >>= 56;
br->bit_pos_ ^= 56; /* here same as -= 56 because of the if condition */ br->bit_pos_ ^= 56; /* here same as -= 56 because of the if condition */
@ -141,7 +144,7 @@ static BROTLI_INLINE void BrotliFillBitWindow(
br->avail_in -= 7; br->avail_in -= 7;
br->next_in += 7; br->next_in += 7;
} }
} else if (IS_CONSTANT(n_bits) && n_bits <= 16) { } else if (!BROTLI_ALIGNED_READ && IS_CONSTANT(n_bits) && (n_bits <= 16)) {
if (br->bit_pos_ >= 48) { if (br->bit_pos_ >= 48) {
br->val_ >>= 48; br->val_ >>= 48;
br->bit_pos_ ^= 48; /* here same as -= 48 because of the if condition */ br->bit_pos_ ^= 48; /* here same as -= 48 because of the if condition */
@ -159,7 +162,7 @@ static BROTLI_INLINE void BrotliFillBitWindow(
} }
} }
#elif (BROTLI_LITTLE_ENDIAN) #elif (BROTLI_LITTLE_ENDIAN)
if (IS_CONSTANT(n_bits) && n_bits <= 8) { if (!BROTLI_ALIGNED_READ && IS_CONSTANT(n_bits) && (n_bits <= 8)) {
if (br->bit_pos_ >= 24) { if (br->bit_pos_ >= 24) {
br->val_ >>= 24; br->val_ >>= 24;
br->bit_pos_ ^= 24; /* here same as -= 24 because of the if condition */ br->bit_pos_ ^= 24; /* here same as -= 24 because of the if condition */
@ -175,23 +178,10 @@ static BROTLI_INLINE void BrotliFillBitWindow(
br->avail_in -= 2; br->avail_in -= 2;
br->next_in += 2; br->next_in += 2;
} }
if (!IS_CONSTANT(n_bits) || (n_bits > 16)) {
if (br->bit_pos_ >= 8) {
br->val_ >>= 8;
br->bit_pos_ ^= 8; /* here same as -= 8 because of the if condition */
br->val_ |= ((uint32_t)*br->next_in) << 24;
--br->avail_in;
++br->next_in;
}
}
} }
#else #else
while (br->bit_pos_ >= 8) { while (br->bit_pos_ >= 16) {
br->val_ >>= 8; BrotliPullByte(br);
br->val_ |= ((uint32_t)*br->next_in) << 24;
br->bit_pos_ -= 8;
--br->avail_in;
++br->next_in;
} }
#endif #endif
} }
@ -246,10 +236,20 @@ static BROTLI_INLINE void BrotliTakeBits(
Assumes that there is enough input to perform BrotliFillBitWindow. */ Assumes that there is enough input to perform BrotliFillBitWindow. */
static BROTLI_INLINE uint32_t BrotliReadBits( static BROTLI_INLINE uint32_t BrotliReadBits(
BrotliBitReader* const br, int n_bits) { BrotliBitReader* const br, int n_bits) {
uint32_t val; if (BROTLI_64_BITS_LITTLE_ENDIAN || (n_bits <= 16)) {
BrotliFillBitWindow(br, n_bits); uint32_t val;
BrotliTakeBits(br, n_bits, &val); BrotliFillBitWindow(br, n_bits);
return val; BrotliTakeBits(br, n_bits, &val);
return val;
} else {
uint32_t low_val;
uint32_t high_val;
BrotliFillBitWindow(br, 16);
BrotliTakeBits(br, 16, &low_val);
BrotliFillBitWindow(br, 8);
BrotliTakeBits(br, n_bits - 16, &high_val);
return low_val | (high_val << 16);
}
} }
/* Tries to read the specified amount of bits. Returns 0, if there is not /* Tries to read the specified amount of bits. Returns 0, if there is not

View File

@ -13,7 +13,15 @@
limitations under the License. limitations under the License.
*/ */
/* Macros for branch prediction. */ /* Macros for compiler / platform specific features and build options.
Build options are:
* BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned
read and overlapping memcpy
* BROTLI_DEBUG dumps file name and line number when decoder detects stream
or memory error
* BROTLI_DECODE_DEBUG enables asserts and dumps various state information
*/
#ifndef BROTLI_DEC_PORT_H_ #ifndef BROTLI_DEC_PORT_H_
#define BROTLI_DEC_PORT_H_ #define BROTLI_DEC_PORT_H_
@ -33,6 +41,12 @@
#define __has_feature(x) 0 #define __has_feature(x) 0
#endif #endif
#ifdef BROTLI_BUILD_PORTABLE
#define BROTLI_ALIGNED_READ 1
#else
#define BROTLI_ALIGNED_READ 0
#endif
#define BROTLI_ASAN_BUILD __has_feature(address_sanitizer) #define BROTLI_ASAN_BUILD __has_feature(address_sanitizer)
/* Define "PREDICT_TRUE" and "PREDICT_FALSE" macros for capable compilers. /* Define "PREDICT_TRUE" and "PREDICT_FALSE" macros for capable compilers.