Conversation
- Bound prefix length k < 30 inside and after the prefix loops in dec_vlc_read_kparam0() and dec_vlc_read_1bit_read(), and accumulate symbol as u32 to avoid signed integer overflow on malformed bitstreams. - Clamp KPARAM_DC, KPARAM_AC, and KPARAM_RUN macros with oapv_clip3(). Signed-off-by: Fyodor Kyslov <kyslov@google.com>
be58705 to
afbd785
Compare
kpchoi
left a comment
There was a problem hiding this comment.
Firstly, Regarding 679 and 719 of your patch,
The in-loop k checks added to dec_vlc_read_kparam0() and dec_vlc_read_1bit_read() are not needed. These loops cannot run forever, even on a malformed bitstream.
- At the end of the buffer,
BSR_FLUSH_1BYTE()does not read past it. It fillscodewith all 1-bits (~(u64)0) and setsis_eob. - The next
BSR_READ_1BIT()then returns 1, soflagbecomes true and the loop exits throughbreak. - Inside these loops
kis only incremented and never used as a shift count. The existing check after the loop rejects too large akbefore it is used.
The error is detected later instead (deferred error checking). The callers test BSR_IS_UNEXPECTED_EOB() after parsing the coefficients and return OAPV_ERR_MALFORMED_BITSTREAM. This is intentional. These two functions are the k = 0 paths and are the ones called most often in coefficient decoding, so a per-bit check in their loops would slow down decoding.
Comments explaining this will be added near these loops.
kpchoi
left a comment
There was a problem hiding this comment.
The oapv_clip3() change to the KPARAM_* macros is not needed either. Their arguments are never negative, and OAPV_KPARAM_*_MIN is 0, so the lower clamp can never take effect:
KPARAM_DC()getsabs_dc_diff, which is at least 1 at that point.KPARAM_AC()getslevel, which is at least 1.KPARAM_RUN()getsrun, which has already been range-checked to[0, OAPV_BLK_D - scan_pos_offset].- On the encoder side, only absolute values are passed.
These macros are evaluated for every coefficient. In VLC decoding even one extra branch or compare per coefficient noticeably affects decoding speed, so oapv_clip3() is intentionally not used here.
| static int dec_vlc_read_kparam0(oapv_bs_t *bs) | ||
| { | ||
| int symbol; | ||
| u32 symbol; |
There was a problem hiding this comment.
Changing symbol from int to u32 is not needed for correctness. The additions are already done in unsigned arithmetic (int + u32, int + u64), so there is no signed overflow. With the k check after the loop, the result always fits in int.
Still, the change is fine to keep as a cosmetic change. It matches dec_vlc_read(), which already uses u32 symbol, and it keeps code reviewers and coding agents from mistaking this pattern for a signed overflow.
| } | ||
| } | ||
| oapv_assert_rv(k < 32, -1); /* prevent too large (impossible) k value */ | ||
| oapv_assert_rv(k < 30, -1); /* prevent too large (impossible) k value */ |
There was a problem hiding this comment.
This is a correct comparison. thanks.
| break; | ||
| } | ||
| else { | ||
| oapv_assert_rv(k < 30, -1); /* prevent too large (impossible) k value */ |
There was a problem hiding this comment.
This line is strongly suggested to be removed because of the reason commented.
| break; | ||
| } | ||
| else { | ||
| oapv_assert_rv(k < 30, -1); /* prevent too large (impossible) k value */ |
There was a problem hiding this comment.
This line is strongly suggested to be removed because of the reason commented.
| #define KPARAM_DC(level) oapv_clip3(OAPV_KPARAM_DC_MIN, OAPV_KPARAM_DC_MAX, (level)>>1) | ||
| #define KPARAM_AC(level) oapv_clip3(OAPV_KPARAM_AC_MIN, OAPV_KPARAM_AC_MAX, (level)>>2) | ||
| #define KPARAM_RUN(run) oapv_clip3(OAPV_KPARAM_RUN_MIN, OAPV_KPARAM_RUN_MAX, (run)>>2) |
There was a problem hiding this comment.
This 3 line are not required to be changed because of the reason commented.
Summary
Bounds exp-Golomb prefix length and clamps
KPARAM_*macros in the VLC coefficient readers:dec_vlc_read_kparam0()&dec_vlc_read_1bit_read()(src/oapv_vlc.c):k < 30inside and after the prefix loops and accumulatesymbolasu32so malformed bitstreams with long zero runs are rejected beforekorsymbolcan overflow.KPARAM_DC,KPARAM_AC,KPARAM_RUN(src/oapv_vlc.h):KPARAM_*macros usingoapv_clip3()to[OAPV_KPARAM_*_MIN, OAPV_KPARAM_*_MAX].Testing
ctestunit/conformance tests pass with AddressSanitizer and UndefinedBehaviorSanitizer.