[FFmpeg-devel] [HACK] fix CAVS decoder crashes
Michael Niedermayer
michaelni
Sun Dec 19 14:47:13 CET 2010
On Sun, Dec 19, 2010 at 12:56:03PM +0100, Reimar D?ffinger wrote:
> On Sat, Dec 18, 2010 at 02:44:40AM +0100, Michael Niedermayer wrote:
> > On Sun, Dec 12, 2010 at 05:04:58PM +0100, Reimar D?ffinger wrote:
> > > Hello,
> > > I have the suspicion this decoder needs heavy fuzzing testing.
> > > Anyway, trying to play http://samples.mplayerhq.hu/AVS/AVSFileFormat/AVSFileFormat.es
> > > results in crashes which below hack "fixes".
> > > Index: libavcodec/cavs.h
> > > ===================================================================
> > > --- libavcodec/cavs.h (revision 25928)
> > > +++ libavcodec/cavs.h (working copy)
> > > @@ -242,6 +242,7 @@
> > > extern const cavs_vector ff_cavs_dir_mv;
> > >
> > > static inline void modify_pred(const int_fast8_t *mod_table, int *mode) {
> > > + if (*mode < 0) *mode = 0;
> > > *mode = mod_table[*mode];
> > > if(*mode < 0) {
> > > av_log(NULL, AV_LOG_ERROR, "Illegal intra prediction mode\n");
> > > Index: libavcodec/cavsdec.c
> > > ===================================================================
> > > --- libavcodec/cavsdec.c (revision 25928)
> > > +++ libavcodec/cavsdec.c (working copy)
> > > @@ -122,7 +122,7 @@
> > >
> > > for(i=0;i<65;i++) {
> > > level_code = get_ue_code(gb,r->golomb_order);
> > > - if(level_code >= ESCAPE_CODE) {
> > > + if(level_code >= ESCAPE_CODE || level_code < 0) {
> > > run = ((level_code - ESCAPE_CODE) >> 1) + 1;
> > > esc_code = get_ue_code(gb,esc_golomb_order);
> > > level = esc_code + (run > r->max_run ? 1 : r->level_add[run]);
> >
> > > @@ -234,7 +234,7 @@
> > > for(block=0;block<4;block++) {
> > > d = h->cy + h->luma_scan[block];
> > > ff_cavs_load_intra_pred_luma(h, top, &left, block);
> > > - h->intra_pred_l[h->pred_mode_Y[ff_cavs_scan3x3[block]]]
> > > + h->intra_pred_l[FFMAX(h->pred_mode_Y[ff_cavs_scan3x3[block]], 0)]
> >
> > as stefan has no time, some comments that might help debuging
> > The intra pred stuff (likely) has to be >= 0 for intra blocks
> > It (likely) is allowed to be negative for non intra blocks
> > i suspect the bug is where this becomes inconsistent (aka intra with negative)
> > a few asserts() might help finding this
>
> They actually seem to come from uninitialized memory, however valgrind had such
> an insane amount of issue with this code that I first had to fix loads of other stuff
> (most of the input validity checks were just not working, and I doubt I caught all).
> Note that using mallocz is definitely wrong, some of those need to be initialized
> to e.g. -1.
> Index: ffmpeg/libavcodec/cavs.c
> ===================================================================
> --- ffmpeg/libavcodec/cavs.c (revision 25928)
> +++ ffmpeg/libavcodec/cavs.c (working copy)
> @@ -577,6 +577,8 @@
> int ff_cavs_next_mb(AVSContext *h) {
> int i;
>
> + if (get_bits_left(&h->s.gb) < 0)
> + return 0;
> h->flags |= A_AVAIL;
> h->cy += 16;
> h->cu += 8;
> @@ -653,17 +655,17 @@
> */
> void ff_cavs_init_top_lines(AVSContext *h) {
> /* alloc top line of predictors */
> - h->top_qp = av_malloc( h->mb_width);
[...]
> + h->top_qp = av_mallocz( h->mb_width);
all uses of top_qp are under B_AVAIL checks so this seems wrong no matter what
value is used in "memset"
ive not checked the other mallocz changes
[...]
> @@ -162,7 +163,7 @@
> int block;
>
> /* get coded block pattern */
> - int cbp= get_ue_golomb(&h->s.gb);
> + unsigned cbp= get_ue_golomb(&h->s.gb);
> if(cbp > 63){
> av_log(h->s.avctx, AV_LOG_ERROR, "illegal inter cbp\n");
> return -1;
Its more work to review a type change to make sure it has no effect except the
comparission. Also the return type is signed so one could argue this is
actually wrong
> @@ -187,9 +188,10 @@
> *
> ****************************************************************************/
>
> -static int decode_mb_i(AVSContext *h, int cbp_code) {
> +static int decode_mb_i(AVSContext *h, unsigned cbp_code) {
> GetBitContext *gb = &h->s.gb;
> - int block, pred_mode_uv;
> + int block;
> + unsigned pred_mode_uv;
> uint8_t top[18];
> uint8_t *left = NULL;
> uint8_t *d;
> @@ -557,11 +559,11 @@
> skip_count = -1;
> if(h->skip_mode_flag && (skip_count < 0))
> skip_count = get_ue_golomb(&s->gb);
> - if(h->skip_mode_flag && skip_count--) {
> + if(h->skip_mode_flag && skip_count-- > 0) {
> decode_mb_p(h,P_SKIP);
> } else {
This is wrong, skip_count must be checked for being valid (<=mb_count id guess)
> mb_type = get_ue_golomb(&s->gb) + P_SKIP + h->skip_mode_flag;
> - if(mb_type > P_8X8)
> + if((unsigned)mb_type > P_8X8)
> decode_mb_i(h, mb_type - P_8X8 - 1);
> else
> decode_mb_p(h,mb_type);
This is a convoluted hack and undocumented too
mb_type should be checked for being valid here and not invalid values being
passed into decode_mb_i() that then detects them checking the cbp and printing
a cbp error while it should be a mb_type error.
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Frequently ignored awnser#1 FFmpeg bugs should be sent to our bugtracker. User
questions about the command line tools should be sent to the ffmpeg-user ML.
And questions about how to use libav* should be sent to the libav-user ML.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20101219/b0605707/attachment.pgp>
More information about the ffmpeg-devel
mailing list