Add try/catch when reading elements with libmatroska.
authorDenis Charmet <typx@dinauz.org>
Sat, 27 Apr 2013 00:44:32 +0000 (02:44 +0200)
committerDenis Charmet <typx@dinauz.org>
Wed, 10 Jul 2013 23:42:42 +0000 (01:42 +0200)
(cherry picked from commit 59c9e8309d5b435a2d85c2c9eaae979ba56ccdd9)

Conflicts:
modules/demux/mkv/matroska_segment.cpp

modules/demux/mkv/demux.cpp
modules/demux/mkv/matroska_segment.cpp
modules/demux/mkv/matroska_segment_parse.cpp

index 0d747b6..225d34e 100644 (file)
@@ -462,16 +462,24 @@ matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, EbmlS
     EbmlElement *p_l0, *p_l1, *p_l2;
     bool b_keep_stream = false, b_keep_segment = false;
 
-    // verify the EBML Header
-    p_l0 = p_estream->FindNextID(EBML_INFO(EbmlHead), UINT64_MAX);
+    /* verify the EBML Header... it shouldn't be bigger than 1kB */
+    p_l0 = p_estream->FindNextID(EBML_INFO(EbmlHead), 1024);
     if (p_l0 == NULL)
     {
         msg_Err( p_demux, "No EBML header found" );
         return NULL;
     }
 
-    // verify we can read this Segment, we only support Matroska version 1 for now
-    p_l0->Read(*p_estream, EBML_CLASS_CONTEXT(EbmlHead), i_upper_lvl, p_l0, true);
+    /* verify we can read this Segment */
+    try
+    {
+        p_l0->Read(*p_estream, EBML_CLASS_CONTEXT(EbmlHead), i_upper_lvl, p_l0, true);
+    }
+    catch(...)
+    {
+        msg_Err(p_demux, "EBML Header Read failed");
+        return NULL;
+    }
 
     EDocType doc_type = GetChild<EDocType>(*static_cast<EbmlHead*>(p_l0));
     if (std::string(doc_type) != "matroska" && std::string(doc_type) != "webm" )
@@ -517,8 +525,15 @@ matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( demux_t *p_demux, EbmlS
                     // find the families of this segment
                     KaxInfo *p_info = static_cast<KaxInfo*>(p_l1);
                     b_keep_segment = b_initial;
-
-                    p_info->Read(*p_estream, EBML_CLASS_CONTEXT(KaxInfo), i_upper_lvl, p_l2, true);
+                    try
+                    {
+                        p_info->Read(*p_estream, EBML_CLASS_CONTEXT(KaxInfo), i_upper_lvl, p_l2, true);
+                    }
+                    catch (...)
+                    {
+                        msg_Err( p_demux, "KaxInfo found but corrupted");
+                        break;
+                    }
                     for( size_t i = 0; i < p_info->ListSize(); i++ )
                     {
                         EbmlElement *l = (*p_info)[i];
index bc99aa6..c607db0 100644 (file)
@@ -120,6 +120,7 @@ matroska_segment_c::~matroska_segment_c()
  *****************************************************************************/
 void matroska_segment_c::LoadCues( KaxCues *cues )
 {
+    bool b_invalid_cue;
     EbmlParser  *ep;
     EbmlElement *el;
 
@@ -134,6 +135,7 @@ void matroska_segment_c::LoadCues( KaxCues *cues )
     {
         if( MKV_IS_ID( el, KaxCuePoint ) )
         {
+            b_invalid_cue = false;
 #define idx p_indexes[i_index]
 
             idx.i_track       = -1;
@@ -148,42 +150,59 @@ void matroska_segment_c::LoadCues( KaxCues *cues )
                 if( MKV_IS_ID( el, KaxCueTime ) )
                 {
                     KaxCueTime &ctime = *(KaxCueTime*)el;
-
-                    ctime.ReadData( es.I_O() );
-
+                    try
+                    {
+                        ctime.ReadData( es.I_O() );
+                    }
+                    catch(...)
+                    {
+                        msg_Err( &sys.demuxer, "Error while reading CueTime" );
+                        b_invalid_cue = true;
+                        break;
+                    }
                     idx.i_time = uint64( ctime ) * i_timescale / (mtime_t)1000;
                 }
                 else if( MKV_IS_ID( el, KaxCueTrackPositions ) )
                 {
                     ep->Down();
-                    while( ( el = ep->Get() ) != NULL )
+                    try
                     {
-                        if( MKV_IS_ID( el, KaxCueTrack ) )
-                        {
-                            KaxCueTrack &ctrack = *(KaxCueTrack*)el;
-
-                            ctrack.ReadData( es.I_O() );
-                            idx.i_track = uint16( ctrack );
-                        }
-                        else if( MKV_IS_ID( el, KaxCueClusterPosition ) )
-                        {
-                            KaxCueClusterPosition &ccpos = *(KaxCueClusterPosition*)el;
-
-                            ccpos.ReadData( es.I_O() );
-                            idx.i_position = segment->GetGlobalPosition( uint64( ccpos ) );
-                        }
-                        else if( MKV_IS_ID( el, KaxCueBlockNumber ) )
+                        while( ( el = ep->Get() ) != NULL )
                         {
-                            KaxCueBlockNumber &cbnum = *(KaxCueBlockNumber*)el;
-
-                            cbnum.ReadData( es.I_O() );
-                            idx.i_block_number = uint32( cbnum );
-                        }
-                        else
-                        {
-                            msg_Dbg( &sys.demuxer, "         * Unknown (%s)", typeid(*el).name() );
+                            if( MKV_IS_ID( el, KaxCueTrack ) )
+                            {
+                                KaxCueTrack &ctrack = *(KaxCueTrack*)el;
+
+                                ctrack.ReadData( es.I_O() );
+                                idx.i_track = uint16( ctrack );
+                            }
+                            else if( MKV_IS_ID( el, KaxCueClusterPosition ) )
+                            {
+                                KaxCueClusterPosition &ccpos = *(KaxCueClusterPosition*)el;
+
+                                ccpos.ReadData( es.I_O() );
+                                idx.i_position = segment->GetGlobalPosition( uint64( ccpos ) );
+                            }
+                            else if( MKV_IS_ID( el, KaxCueBlockNumber ) )
+                            {
+                                KaxCueBlockNumber &cbnum = *(KaxCueBlockNumber*)el;
+
+                                cbnum.ReadData( es.I_O() );
+                                idx.i_block_number = uint32( cbnum );
+                            }
+                            else
+                            {
+                                msg_Dbg( &sys.demuxer, "         * Unknown (%s)", typeid(*el).name() );
+                            }
                         }
                     }
+                    catch(...)
+                    {
+                        ep->Up();   
+                        msg_Err( &sys.demuxer, "Error while reading %s", typeid(*el).name() );
+                        b_invalid_cue = true;
+                        break;
+                    }
                     ep->Up();
                 }
                 else
@@ -198,13 +217,15 @@ void matroska_segment_c::LoadCues( KaxCues *cues )
                      " track=%d bnum=%d", idx.i_time, idx.i_position,
                      idx.i_track, idx.i_block_number );
 #endif
-
-            i_index++;
-            if( i_index >= i_index_max )
+            if( likely( !b_invalid_cue ) )
             {
-                i_index_max += 1024;
-                p_indexes = (mkv_index_t*)xrealloc( p_indexes,
-                                        sizeof( mkv_index_t ) * i_index_max );
+                i_index++;
+                if( i_index >= i_index_max )
+                {
+                    i_index_max += 1024;
+                    p_indexes = (mkv_index_t*)xrealloc( p_indexes,
+                                                        sizeof( mkv_index_t ) * i_index_max );
+                }
             }
 #undef idx
         }
@@ -254,21 +275,32 @@ void matroska_segment_c::ParseSimpleTags( KaxTagSimple *tag )
         sys.meta = vlc_meta_New();
 
     msg_Dbg( &sys.demuxer, "|   + Simple Tag ");
-    while( ( el = ep->Get() ) != NULL )
+    try
     {
-        if( MKV_IS_ID( el, KaxTagName ) )
-        {
-            KaxTagName &key = *(KaxTagName*)el;
-            key.ReadData( es.I_O(), SCOPE_ALL_DATA );
-            k = strdup( UTFstring( key ).GetUTF8().c_str() );
-        }
-        if( MKV_IS_ID( el, KaxTagString ) )
+        while( ( el = ep->Get() ) != NULL )
         {
-            KaxTagString &value = *(KaxTagString*)el;
-            value.ReadData( es.I_O(), SCOPE_ALL_DATA );
-            v = strdup( UTFstring( value ).GetUTF8().c_str() );
+            if( MKV_IS_ID( el, KaxTagName ) )
+            {
+                KaxTagName &key = *(KaxTagName*)el;
+                key.ReadData( es.I_O(), SCOPE_ALL_DATA );
+                k = strdup( UTFstring( key ).GetUTF8().c_str() );
+            }
+            else if( MKV_IS_ID( el, KaxTagString ) )
+            {
+                KaxTagString &value = *(KaxTagString*)el;
+                value.ReadData( es.I_O(), SCOPE_ALL_DATA );
+                v = strdup( UTFstring( value ).GetUTF8().c_str() );
+            }
         }
     }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Error while reading Tag ");
+        free(k);
+        free(v);
+        delete ep;
+        return;
+    }
     delete ep;
 
     if( !k || !v )
@@ -1502,109 +1534,117 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s
         }
 
         /* do parsing */
-        switch ( i_level )
+        try
         {
-        case 1:
-            if( MKV_IS_ID( el, KaxCluster ) )
+            switch ( i_level )
             {
-                cluster = (KaxCluster*)el;
-                i_cluster_pos = cluster->GetElementPosition();
+                case 1:
+                    if( MKV_IS_ID( el, KaxCluster ) )
+                    {
+                        cluster = (KaxCluster*)el;
+                        i_cluster_pos = cluster->GetElementPosition();
 
-                // reset silent tracks
-                for (size_t i=0; i<tracks.size(); i++)
-                {
-                    tracks[i]->b_silent = false;
-                }
+                        // reset silent tracks
+                        for (size_t i=0; i<tracks.size(); i++)
+                        {
+                            tracks[i]->b_silent = false;
+                        }
 
-                ep->Down();
-            }
-            else if( MKV_IS_ID( el, KaxCues ) )
-            {
-                msg_Warn( &sys.demuxer, "find KaxCues FIXME" );
-                return VLC_EGENERIC;
-            }
-            else
-            {
-                msg_Dbg( &sys.demuxer, "unknown (%s)", typeid( el ).name() );
-            }
-            break;
-        case 2:
-            if( MKV_IS_ID( el, KaxClusterTimecode ) )
-            {
-                KaxClusterTimecode &ctc = *(KaxClusterTimecode*)el;
+                        ep->Down();
+                    }
+                    else if( MKV_IS_ID( el, KaxCues ) )
+                    {
+                        msg_Warn( &sys.demuxer, "find KaxCues FIXME" );
+                        return VLC_EGENERIC;
+                    }
+                    else
+                    {
+                        msg_Dbg( &sys.demuxer, "unknown (%s)", typeid( el ).name() );
+                    }
+                    break;
+                case 2:
+                    if( MKV_IS_ID( el, KaxClusterTimecode ) )
+                    {
+                        KaxClusterTimecode &ctc = *(KaxClusterTimecode*)el;
 
-                ctc.ReadData( es.I_O(), SCOPE_ALL_DATA );
-                cluster->InitTimecode( uint64( ctc ), i_timescale );
-                /* add it to the index */
-                if( i_index == 0 ||
-                    ( i_index > 0 &&
-                      p_indexes[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
-                    IndexAppendCluster( cluster );
-            }
-            else if( MKV_IS_ID( el, KaxClusterSilentTracks ) )
-            {
-                ep->Down();
-            }
-            else if( MKV_IS_ID( el, KaxBlockGroup ) )
-            {
-                i_block_pos = el->GetElementPosition();
-                ep->Down();
-            }
-            else if( MKV_IS_ID( el, KaxSimpleBlock ) )
-            {
-                pp_simpleblock = (KaxSimpleBlock*)el;
+                        ctc.ReadData( es.I_O(), SCOPE_ALL_DATA );
+                        cluster->InitTimecode( uint64( ctc ), i_timescale );
 
-                pp_simpleblock->ReadData( es.I_O() );
-                pp_simpleblock->SetParent( *cluster );
-            }
-            break;
-        case 3:
-            if( MKV_IS_ID( el, KaxBlock ) )
-            {
-                pp_block = (KaxBlock*)el;
+                        /* add it to the index */
+                        if( i_index == 0 ||
+                            ( i_index > 0 &&
+                              p_indexes[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
+                            IndexAppendCluster( cluster );
+                    }
+                    else if( MKV_IS_ID( el, KaxClusterSilentTracks ) )
+                    {
+                        ep->Down();
+                    }
+                    else if( MKV_IS_ID( el, KaxBlockGroup ) )
+                    {
+                        i_block_pos = el->GetElementPosition();
+                        ep->Down();
+                    }
+                    else if( MKV_IS_ID( el, KaxSimpleBlock ) )
+                    {
+                        pp_simpleblock = (KaxSimpleBlock*)el;
 
-                pp_block->ReadData( es.I_O() );
-                pp_block->SetParent( *cluster );
+                        pp_simpleblock->ReadData( es.I_O() );
+                        pp_simpleblock->SetParent( *cluster );
+                    }
+                    break;
+                case 3:
+                    if( MKV_IS_ID( el, KaxBlock ) )
+                    {
+                        pp_block = (KaxBlock*)el;
 
-                ep->Keep();
-            }
-            else if( MKV_IS_ID( el, KaxBlockDuration ) )
-            {
-                KaxBlockDuration &dur = *(KaxBlockDuration*)el;
+                        pp_block->ReadData( es.I_O() );
+                        pp_block->SetParent( *cluster );
 
-                dur.ReadData( es.I_O() );
-                *pi_duration = uint64( dur );
-            }
-            else if( MKV_IS_ID( el, KaxReferenceBlock ) )
-            {
-                KaxReferenceBlock &ref = *(KaxReferenceBlock*)el;
+                        ep->Keep();
+                    }
+                    else if( MKV_IS_ID( el, KaxBlockDuration ) )
+                    {
+                        KaxBlockDuration &dur = *(KaxBlockDuration*)el;
 
-                ref.ReadData( es.I_O() );
+                        dur.ReadData( es.I_O() );
+                        *pi_duration = uint64( dur );
+                    }
+                    else if( MKV_IS_ID( el, KaxReferenceBlock ) )
+                    {
+                        KaxReferenceBlock &ref = *(KaxReferenceBlock*)el;
 
-                if( *pb_key_picture )
-                    *pb_key_picture = false;
-                else if( int64( ref ) > 0 )
-                    *pb_discardable_picture = true;
-            }
-            else if( MKV_IS_ID( el, KaxClusterSilentTrackNumber ) )
-            {
-                KaxClusterSilentTrackNumber &track_num = *(KaxClusterSilentTrackNumber*)el;
-                track_num.ReadData( es.I_O() );
-                // find the track
-                for (size_t i=0; i<tracks.size(); i++)
-                {
-                    if ( tracks[i]->i_number == uint32(track_num))
+                        ref.ReadData( es.I_O() );
+
+                        if( *pb_key_picture )
+                            *pb_key_picture = false;
+                        else if( int64( ref ) > 0 )
+                            *pb_discardable_picture = true;
+                    }
+                    else if( MKV_IS_ID( el, KaxClusterSilentTrackNumber ) )
                     {
-                        tracks[i]->b_silent = true;
-                        break;
+                        KaxClusterSilentTrackNumber &track_num = *(KaxClusterSilentTrackNumber*)el;
+                        track_num.ReadData( es.I_O() );
+                        // find the track
+                        for (size_t i=0; i<tracks.size(); i++)
+                        {
+                            if ( tracks[i]->i_number == uint32(track_num))
+                            {
+                                tracks[i]->b_silent = true;
+                                break;
+                            }
+                        }
                     }
-                }
+                    break;
+                default:
+                    msg_Err( &sys.demuxer, "invalid level = %d", i_level );
+                    return VLC_EGENERIC;
             }
-            break;
-        default:
-            msg_Err( &sys.demuxer, "invalid level = %d", i_level );
-            return VLC_EGENERIC;
+        }
+        catch(...)
+        {
+            msg_Err( &sys.demuxer, "Error while reading %s... upping level", typeid(*el).name());
+            ep->Up();
         }
     }
 }
index 1cac799..862c42c 100644 (file)
@@ -66,26 +66,33 @@ void matroska_segment_c::ParseSeekHead( KaxSeekHead *seekhead )
             msg_Dbg( &sys.demuxer, "|   |   + Seek" );
 #endif
             ep->Down();
-            while( ( l = ep->Get() ) != NULL )
+            try
             {
-                if( MKV_IS_ID( l, KaxSeekID ) )
+                while( ( l = ep->Get() ) != NULL )
                 {
-                    KaxSeekID &sid = *(KaxSeekID*)l;
-                    sid.ReadData( es.I_O() );
-                    id = EbmlId( sid.GetBuffer(), sid.GetSize() );
-                }
-                else if( MKV_IS_ID( l, KaxSeekPosition ) )
-                {
-                    KaxSeekPosition &spos = *(KaxSeekPosition*)l;
-                    spos.ReadData( es.I_O() );
-                    i_pos = (int64_t)segment->GetGlobalPosition( uint64( spos ) );
-                }
-                else
-                {
-                    /* Many mkvmerge files hit this case. It seems to be a broken SeekHead */
-                    msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name()  );
+                    if( MKV_IS_ID( l, KaxSeekID ) )
+                    {
+                        KaxSeekID &sid = *(KaxSeekID*)l;
+                        sid.ReadData( es.I_O() );
+                        id = EbmlId( sid.GetBuffer(), sid.GetSize() );
+                    }
+                    else if( MKV_IS_ID( l, KaxSeekPosition ) )
+                    {
+                        KaxSeekPosition &spos = *(KaxSeekPosition*)l;
+                        spos.ReadData( es.I_O() );
+                        i_pos = (int64_t)segment->GetGlobalPosition( uint64( spos ) );
+                    }
+                    else
+                    {
+                        /* Many mkvmerge files hit this case. It seems to be a broken SeekHead */
+                        msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
+                    }
                 }
             }
+            catch(...)
+            {
+                msg_Err( &sys.demuxer,"Error while reading %s",  typeid(*l).name() );
+            }
             ep->Up();
 
             if( i_pos >= 0 )
@@ -668,7 +675,15 @@ void matroska_segment_c::ParseTracks( KaxTracks *tracks )
     int i_upper_level = 0;
 
     /* Master elements */
-    tracks->Read( es, EBML_CONTEXT(tracks), i_upper_level, el, true );
+    try
+    {
+        tracks->Read( es, EBML_CONTEXT(tracks), i_upper_level, el, true );
+    }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Couldn't read tracks" );
+        return;
+    }
 
     for( size_t i = 0; i < tracks->ListSize(); i++ )
     {
@@ -696,7 +711,15 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
 
     /* Master elements */
     m = static_cast<EbmlMaster *>(info);
-    m->Read( es, EBML_CONTEXT(info), i_upper_level, el, true );
+    try
+    {
+        m->Read( es, EBML_CONTEXT(info), i_upper_level, el, true );
+    }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Couldn't read info" );
+        return;
+    }   
 
     for( size_t i = 0; i < m->ListSize(); i++ )
     {
@@ -809,28 +832,35 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
         else if( MKV_IS_ID( l, KaxChapterTranslate ) )
         {
             KaxChapterTranslate *p_trans = static_cast<KaxChapterTranslate*>( l );
-            chapter_translation_c *p_translate = new chapter_translation_c();
-
-            p_trans->Read( es, EBML_CONTEXT(p_trans), i_upper_level, el, true );
-            for( size_t j = 0; j < p_trans->ListSize(); j++ )
+            try
             {
-                EbmlElement *l = (*p_trans)[j];
+                p_trans->Read( es, EBML_CONTEXT(p_trans), i_upper_level, el, true );
+                chapter_translation_c *p_translate = new chapter_translation_c();
 
-                if( MKV_IS_ID( l, KaxChapterTranslateEditionUID ) )
-                {
-                    p_translate->editions.push_back( uint64( *static_cast<KaxChapterTranslateEditionUID*>( l ) ) );
-                }
-                else if( MKV_IS_ID( l, KaxChapterTranslateCodec ) )
-                {
-                    p_translate->codec_id = uint32( *static_cast<KaxChapterTranslateCodec*>( l ) );
-                }
-                else if( MKV_IS_ID( l, KaxChapterTranslateID ) )
+                for( size_t j = 0; j < p_trans->ListSize(); j++ )
                 {
-                    p_translate->p_translated = new KaxChapterTranslateID( *static_cast<KaxChapterTranslateID*>( l ) );
+                    EbmlElement *l = (*p_trans)[j];
+
+                    if( MKV_IS_ID( l, KaxChapterTranslateEditionUID ) )
+                    {
+                        p_translate->editions.push_back( uint64( *static_cast<KaxChapterTranslateEditionUID*>( l ) ) );
+                    }
+                    else if( MKV_IS_ID( l, KaxChapterTranslateCodec ) )
+                    {
+                        p_translate->codec_id = uint32( *static_cast<KaxChapterTranslateCodec*>( l ) );
+                    }
+                    else if( MKV_IS_ID( l, KaxChapterTranslateID ) )
+                    {
+                        p_translate->p_translated = new KaxChapterTranslateID( *static_cast<KaxChapterTranslateID*>( l ) );
+                    }
                 }
-            }
 
-            translations.push_back( p_translate );
+                translations.push_back( p_translate );
+            }
+            catch(...)
+            {
+                msg_Err( &sys.demuxer, "Error while reading Chapter Tranlate");
+            }
         }
         else
         {
@@ -994,7 +1024,15 @@ void matroska_segment_c::ParseAttachments( KaxAttachments *attachments )
     EbmlElement *el;
     int i_upper_level = 0;
 
-    attachments->Read( es, EBML_CONTEXT(attachments), i_upper_level, el, true );
+    try
+    {
+        attachments->Read( es, EBML_CONTEXT(attachments), i_upper_level, el, true );
+    }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Error while reading attachments" );
+        return;
+    }
 
     KaxAttached *attachedFile = FindChild<KaxAttached>( *attachments );
 
@@ -1041,7 +1079,15 @@ void matroska_segment_c::ParseChapters( KaxChapters *chapters )
     int i_upper_level = 0;
 
     /* Master elements */
-    chapters->Read( es, EBML_CONTEXT(chapters), i_upper_level, el, true );
+    try
+    {
+        chapters->Read( es, EBML_CONTEXT(chapters), i_upper_level, el, true );
+    }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Error while reading chapters" );
+        return;
+    }
 
     for( size_t i = 0; i < chapters->ListSize(); i++ )
     {
@@ -1102,7 +1148,15 @@ void matroska_segment_c::ParseCluster( bool b_update_start_time )
 
     /* Master elements */
     m = static_cast<EbmlMaster *>( cluster );
-    m->Read( es, EBML_CONTEXT(cluster), i_upper_level, el, true );
+    try
+    {
+        m->Read( es, EBML_CONTEXT(cluster), i_upper_level, el, true );
+    }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Error while reading cluster" );
+        return;
+    }
 
     for( unsigned int i = 0; i < m->ListSize(); i++ )
     {