[vlc-commits] input: es_out: split slave es list

Francois Cartegnie git at videolan.org
Fri Jun 29 14:49:20 CEST 2018


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Fri Jun 29 11:41:05 2018 +0200| [3ea59e2906473bc4767d77a62d3d32677b55fd0b] | committer: Francois Cartegnie

input: es_out: split slave es list

fixes use after free since vlc_list
cb09ab2cf7cf762cd20436be73b74495407de2450 change.
Can't work with list iterator since the current
es will modify the es slaves list.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=3ea59e2906473bc4767d77a62d3d32677b55fd0b
---

 src/input/es_out.c | 72 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 44 insertions(+), 28 deletions(-)

diff --git a/src/input/es_out.c b/src/input/es_out.c
index 7b115ffb52..5c78303912 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -139,6 +139,7 @@ typedef struct
     /* all es */
     int         i_id;
     struct vlc_list es;
+    struct vlc_list es_slaves; /* Dynamically created es on regular es selection */
 
     /* mode gestion */
     bool  b_active;
@@ -224,6 +225,11 @@ static inline bool EsFmtIsTeletext( const es_format_t *p_fmt )
     return p_fmt->i_cat == SPU_ES && p_fmt->i_codec == VLC_CODEC_TELETEXT;
 }
 
+#define foreach_es_then_es_slaves( pos ) \
+    for( int fetes_i=0; fetes_i<2; fetes_i++ ) \
+        vlc_list_foreach( pos, (!fetes_i ? &p_sys->es : &p_sys->es_slaves), node )
+
+
 /*****************************************************************************
  * Es category specific structs
  *****************************************************************************/
@@ -303,6 +309,7 @@ es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
 
     vlc_list_init(&p_sys->programs);
     vlc_list_init(&p_sys->es);
+    vlc_list_init(&p_sys->es_slaves);
 
     /* */
     EsOutPropsInit( &p_sys->video, true, p_input, ES_OUT_ES_POLICY_SIMULTANEOUS,
@@ -333,6 +340,7 @@ static void EsOutDelete( es_out_t *out )
     es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
 
     assert(vlc_list_is_empty(&p_sys->es));
+    assert(vlc_list_is_empty(&p_sys->es_slaves));
     assert(vlc_list_is_empty(&p_sys->programs));
     assert(p_sys->p_pgrm == NULL);
     EsOutPropsCleanup( &p_sys->audio );
@@ -351,7 +359,7 @@ static void EsOutTerminate( es_out_t *out )
     if( p_sys->p_sout_record )
         EsOutSetRecord( out, false );
 
-    vlc_list_foreach(es, &p_sys->es, node)
+    foreach_es_then_es_slaves(es)
     {
         if (es->p_dec != NULL)
             input_DecoderDelete(es->p_dec);
@@ -415,7 +423,7 @@ static es_out_id_t *EsOutGetFromID( es_out_t *out, int i_id )
         return es_cat - i_id;
     }
 
-    vlc_list_foreach(es, &p_sys->es, node)
+    foreach_es_then_es_slaves(es)
         if (es->i_id == i_id)
             return es;
     return NULL;
@@ -433,7 +441,7 @@ static bool EsOutDecodersIsEmpty( es_out_t *out )
             return true;
     }
 
-    vlc_list_foreach(es, &p_sys->es, node)
+    foreach_es_then_es_slaves(es)
     {
         if( es->p_dec && !input_DecoderIsEmpty( es->p_dec ) )
             return false;
@@ -453,7 +461,7 @@ static void EsOutSetDelay( es_out_t *out, int i_cat, vlc_tick_t i_delay )
     else if( i_cat == SPU_ES )
         p_sys->i_spu_delay = i_delay;
 
-    vlc_list_foreach(es, &p_sys->es, node)
+    foreach_es_then_es_slaves(es)
         EsOutDecoderChangeDelay(out, es);
 }
 
@@ -508,9 +516,9 @@ static int EsOutSetRecord(  es_out_t *out, bool b_record )
         if( !p_sys->p_sout_record )
             return VLC_EGENERIC;
 
-        vlc_list_foreach(p_es, &p_sys->es, node)
+        vlc_list_foreach( p_es, &p_sys->es, node ) /* Only master es */
         {
-            if( !p_es->p_dec || p_es->p_master )
+            if( !p_es->p_dec )
                 continue;
 
             p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_input_clock, p_sys->p_sout_record );
@@ -520,7 +528,7 @@ static int EsOutSetRecord(  es_out_t *out, bool b_record )
     }
     else
     {
-        vlc_list_foreach(p_es, &p_sys->es, node)
+        vlc_list_foreach( p_es, &p_sys->es, node ) /* Only master es */
         {
             if( !p_es->p_dec_record )
                 continue;
@@ -586,7 +594,7 @@ static void EsOutChangeRate( es_out_t *out, int i_rate )
     p_sys->i_rate = i_rate;
     EsOutProgramsChangeRate( out );
 
-    vlc_list_foreach(es, &p_sys->es, node)
+    foreach_es_then_es_slaves(es)
         if( es->p_dec != NULL )
             input_DecoderChangeRate( es->p_dec, rate );
 }
@@ -598,7 +606,7 @@ static void EsOutChangePosition( es_out_t *out )
 
     input_SendEventCache( p_sys->p_input, 0.0 );
 
-    vlc_list_foreach(p_es, &p_sys->es, node)
+    foreach_es_then_es_slaves(p_es)
         if( p_es->p_dec != NULL )
         {
             input_DecoderFlush( p_es->p_dec );
@@ -679,7 +687,7 @@ static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
     }
 
     const vlc_tick_t i_decoder_buffering_start = vlc_tick_now();
-    vlc_list_foreach(p_es, &p_sys->es, node)
+    foreach_es_then_es_slaves(p_es)
     {
         if( !p_es->p_dec || p_es->fmt.i_cat == SPU_ES )
             continue;
@@ -701,7 +709,7 @@ static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
     input_clock_ChangeSystemOrigin( p_sys->p_pgrm->p_input_clock, true,
                                     i_current_date + i_wakeup_delay - i_buffering_duration );
 
-    vlc_list_foreach(p_es, &p_sys->es, node)
+    foreach_es_then_es_slaves(p_es)
     {
         if( !p_es->p_dec )
             continue;
@@ -717,7 +725,7 @@ static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, vlc_tick_t i
     es_out_id_t *es;
 
     /* Pause decoders first */
-    vlc_list_foreach(es, &p_sys->es, node)
+    foreach_es_then_es_slaves(es)
         if( es->p_dec )
         {
             input_DecoderChangePause( es->p_dec, b_paused, i_date );
@@ -732,7 +740,7 @@ static bool EsOutIsExtraBufferingAllowed( es_out_t *out )
     es_out_id_t *p_es;
 
     size_t i_size = 0;
-    vlc_list_foreach(p_es, &p_sys->es, node)
+    foreach_es_then_es_slaves(p_es)
     {
         if( p_es->p_dec )
             i_size += input_DecoderGetFifoSize( p_es->p_dec );
@@ -798,8 +806,8 @@ static void EsOutFrameNext( es_out_t *out )
 
     assert( p_sys->b_paused );
 
-    vlc_list_foreach(p_es, &p_sys->es, node)
-        if( p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
+    foreach_es_then_es_slaves(p_es)
+        if( p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec && !p_es_video /* nested loop */ )
         {
             p_es_video = p_es;
             break;
@@ -1004,7 +1012,7 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
 
         msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
 
-        vlc_list_foreach(es, &p_sys->es, node)
+        foreach_es_then_es_slaves(es)
             if (es->p_pgrm == old && EsIsSelected(es)
              && p_sys->i_mode != ES_OUT_MODE_ALL)
                 EsUnselect(out, es, true);
@@ -1035,7 +1043,7 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
     /* TODO event */
     var_SetInteger( p_input, "teletext-es", -1 );
 
-    vlc_list_foreach(es, &p_sys->es, node)
+    foreach_es_then_es_slaves(es)
     {
         if (es->p_pgrm == p_sys->p_pgrm)
         {
@@ -1439,7 +1447,7 @@ static void EsOutProgramUpdateScrambled( es_out_t *p_out, es_out_pgrm_t *p_pgrm
     es_out_id_t *es;
     bool b_scrambled = false;
 
-    vlc_list_foreach(es, &p_sys->es, node)
+    vlc_list_foreach( es, &p_sys->es, node ) /* Only master es */
         if (es->p_pgrm == p_pgrm && es->b_scrambled)
         {
             b_scrambled = true;
@@ -1622,7 +1630,7 @@ static es_out_id_t *EsOutAddSlave( es_out_t *out, const es_format_t *fmt, es_out
     es->cc.i_bitmap = 0;
     es->p_master = p_master;
 
-    vlc_list_append(&es->node, &p_sys->es);
+    vlc_list_append(&es->node, es->p_master ? &p_sys->es_slaves : &p_sys->es);
 
     if( es->p_pgrm == p_sys->p_pgrm )
         EsOutESVarUpdate( out, es, false );
@@ -2191,7 +2199,7 @@ static void EsOutDel( es_out_t *out, es_out_id_t *es )
     {
         es_out_id_t *other;
 
-        vlc_list_foreach(other, &p_sys->es, node)
+        foreach_es_then_es_slaves(other)
             if( es->fmt.i_cat == other->fmt.i_cat )
             {
                 if (EsIsSelected(other))
@@ -2289,8 +2297,8 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
             es_out_id_t *p_es;
             bool found = false;
 
-            vlc_list_foreach(p_es, &p_sys->es, node)
-                if( p_es->fmt.i_cat == VIDEO_ES )
+            foreach_es_then_es_slaves(p_es)
+                if( p_es->fmt.i_cat == VIDEO_ES && !found /* nested loop */ )
                 {
                     found = true;
                     break;
@@ -2304,11 +2312,17 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
 
         /* Reapply policy mode */
         es_out_id_t *es;
-        vlc_list_foreach(es, &p_sys->es, node)
+
+        foreach_es_then_es_slaves(es)
+        {
             if (EsIsSelected(es))
                 EsUnselect(out, es, es->p_pgrm == p_sys->p_pgrm);
-        vlc_list_foreach(es, &p_sys->es, node)
+        }
+        foreach_es_then_es_slaves(es)
+        {
             EsOutSelect(out, es, false);
+        }
+
         if( i_mode == ES_OUT_MODE_END )
             EsOutTerminate( out );
         return VLC_SUCCESS;
@@ -2332,7 +2346,8 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
         else
             i_cat = IGNORE_ES;
 
-        vlc_list_foreach(other, &p_sys->es, node)
+        foreach_es_then_es_slaves(other)
+        {
             if( i_cat == IGNORE_ES )
             {
                 if (es == other)
@@ -2365,6 +2380,7 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
                         EsUnselect(out, other, other->p_pgrm == p_sys->p_pgrm);
                 }
             }
+        }
 
         return VLC_SUCCESS;
     }
@@ -2373,7 +2389,7 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
         es_out_id_t *es;
         int count = 0;
 
-        vlc_list_foreach(es, &p_sys->es, node)
+        foreach_es_then_es_slaves(es)
             count++;
 
         int *selected_es = vlc_alloc(count + 1, sizeof(int));
@@ -2383,7 +2399,7 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
         *va_arg(args, void **) = selected_es;
         *selected_es = count;
 
-        vlc_list_foreach(es, &p_sys->es, node)
+        foreach_es_then_es_slaves(es)
         {
             if (EsIsSelected(es))
             {
@@ -2849,7 +2865,7 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
     case ES_OUT_SET_EOS:
     {
         es_out_id_t *id;
-        vlc_list_foreach(id, &p_sys->es, node)
+        foreach_es_then_es_slaves(id)
             if (id->p_dec != NULL)
                 input_DecoderDrain(id->p_dec);
         return VLC_SUCCESS;



More information about the vlc-commits mailing list