Fix 32 bit writing in VP8LPutBits

>>32 is undefined. VP8LPutBits is never called for 32 bits in the
pipeline though.

Change-Id: I11f0a4c15380ab94213adab25f06b2ab73e73519
This commit is contained in:
Vincent Rabaud
2025-10-01 09:15:34 +02:00
parent 0e5f4ee3de
commit 1f0a494e80
2 changed files with 47 additions and 52 deletions

View File

@@ -275,7 +275,8 @@ void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst) {
*dst = tmp;
}
void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) {
void VP8LPutBitsFlushBits(VP8LBitWriter* const bw, int* used,
vp8l_atype_t* bits) {
// If needed, make some room by flushing some bits out.
if (bw->cur + VP8L_WRITER_BYTES > bw->end) {
const uint64_t extra_size = (bw->end - bw->buf) + MIN_EXTRA_SIZE;
@@ -286,51 +287,42 @@ void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) {
return;
}
}
*(vp8l_wtype_t*)bw->cur = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)bw->bits);
*(vp8l_wtype_t*)bw->cur = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)*bits);
bw->cur += VP8L_WRITER_BYTES;
bw->bits >>= VP8L_WRITER_BITS;
bw->used -= VP8L_WRITER_BITS;
*bits >>= VP8L_WRITER_BITS;
*used -= VP8L_WRITER_BITS;
}
void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) {
assert(n_bits <= 32);
// That's the max we can handle:
assert(sizeof(vp8l_wtype_t) == 2);
if (n_bits > 0) {
vp8l_atype_t lbits = bw->bits;
int used = bw->used;
// Special case of overflow handling for 32bit accumulator (2-steps flush).
#if VP8L_WRITER_BITS == 16
if (used + n_bits >= VP8L_WRITER_MAX_BITS) {
// Fill up all the VP8L_WRITER_MAX_BITS so it can be flushed out below.
const int shift = VP8L_WRITER_MAX_BITS - used;
lbits |= (vp8l_atype_t)bits << used;
used = VP8L_WRITER_MAX_BITS;
n_bits -= shift;
void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) {
vp8l_atype_t lbits = bw->bits;
int used = bw->used;
assert(n_bits <= VP8L_WRITER_MAX_BITS);
if (n_bits == 0) return;
// Special case of overflow handling for 32bit accumulator (2-steps flush).
if (used + n_bits >= VP8L_WRITER_MAX_BITS) {
// Fill up all the VP8L_WRITER_MAX_BITS so it can be flushed out below.
const int shift = VP8L_WRITER_MAX_BITS - used;
lbits |= (vp8l_atype_t)bits << used;
used = VP8L_WRITER_MAX_BITS;
n_bits -= shift;
if (shift >= (int)sizeof(bits) * 8) {
// Undefined behavior.
assert(shift == (int)sizeof(bits) * 8);
bits = 0;
} else {
bits >>= shift;
assert(n_bits <= VP8L_WRITER_MAX_BITS);
}
#endif
// If needed, make some room by flushing some bits out.
while (used >= VP8L_WRITER_BITS) {
if (bw->cur + VP8L_WRITER_BYTES > bw->end) {
const uint64_t extra_size = (bw->end - bw->buf) + MIN_EXTRA_SIZE;
if (!CheckSizeOverflow(extra_size) ||
!VP8LBitWriterResize(bw, (size_t)extra_size)) {
bw->cur = bw->buf;
bw->error = 1;
return;
}
}
*(vp8l_wtype_t*)bw->cur = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)lbits);
bw->cur += VP8L_WRITER_BYTES;
lbits >>= VP8L_WRITER_BITS;
used -= VP8L_WRITER_BITS;
}
bw->bits = lbits | ((vp8l_atype_t)bits << used);
bw->used = used + n_bits;
assert(n_bits <= VP8L_WRITER_MAX_BITS);
}
// If needed, make some room by flushing some bits out.
while (used >= VP8L_WRITER_BITS) {
VP8LPutBitsFlushBits(bw, &used, &lbits);
}
bw->bits = lbits | ((vp8l_atype_t)bits << used);
bw->used = used + n_bits;
}
#endif // VP8L_WRITER_BITS == 16
uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw) {
// flush leftover bits

View File

@@ -125,30 +125,33 @@ void VP8LBitWriterReset(const VP8LBitWriter* const bw_init,
// Swaps the memory held by two BitWriters.
void VP8LBitWriterSwap(VP8LBitWriter* const src, VP8LBitWriter* const dst);
// Internal function for VP8LPutBits flushing 32 bits from the written state.
void VP8LPutBitsFlushBits(VP8LBitWriter* const bw);
// Internal function for VP8LPutBits flushing VP8L_WRITER_BITS bits from the
// written state.
void VP8LPutBitsFlushBits(VP8LBitWriter* const bw, int* used,
vp8l_atype_t* bits);
#if VP8L_WRITER_BITS == 16
// PutBits internal function used in the 16 bit vp8l_wtype_t case.
void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits);
#endif
// This function writes bits into bytes in increasing addresses (little endian),
// and within a byte least-significant-bit first.
// This function can write up to 32 bits in one go, but VP8LBitReader can only
// read 24 bits max (VP8L_MAX_NUM_BIT_READ).
// This function can write up to VP8L_WRITER_MAX_BITS bits in one go, but
// VP8LBitReader can only read 24 bits max (VP8L_MAX_NUM_BIT_READ).
// VP8LBitWriter's 'error' flag is set in case of memory allocation error.
static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw, uint32_t bits,
int n_bits) {
if (sizeof(vp8l_wtype_t) == 4) {
if (n_bits > 0) {
if (bw->used >= 32) {
VP8LPutBitsFlushBits(bw);
}
bw->bits |= (vp8l_atype_t)bits << bw->used;
bw->used += n_bits;
}
} else {
VP8LPutBitsInternal(bw, bits, n_bits);
#if VP8L_WRITER_BYTES == 4
if (n_bits == 0) return;
if (bw->used >= VP8L_WRITER_BITS) {
VP8LPutBitsFlushBits(bw, &bw->used, &bw->bits);
}
bw->bits |= (vp8l_atype_t)bits << bw->used;
bw->used += n_bits;
#else
VP8LPutBitsInternal(bw, bits, n_bits);
#endif
}
//------------------------------------------------------------------------------