demux: avformat: fix tracks initialization to prevent crash
authorRomain Vimont <rom@rom1v.com>
Wed, 1 Nov 2017 00:04:31 +0000 (01:04 +0100)
committerThomas Guillem <thomas@gllm.fr>
Wed, 1 Nov 2017 08:30:19 +0000 (09:30 +0100)
The 'tracks' array was created before the possible update of nb_streams
in avformat_find_stream_info(). As a consequence, it was then accessed
out of bounds.

On the following video, nb_streams is updated from 0 to 2 by
avformat_find_stream_info():

    $ youtube-dl https://bambuser.com/v/6908002 -o sample.flv
    ...
    $ ./vlc sample.flv
    *** Error in `./vlc': free(): invalid next size (fast): 0x00007f85f4c376a0 ***
    ...

bisect/bad is 6cb816a2556937e63f49d5e703b98e2a760419ec.

Signed-off-by: Romain Vimont <rom@rom1v.com>
Signed-off-by: Thomas Guillem <thomas@gllm.fr>
modules/demux/avformat/demux.c

index 9b242b0..2f3b907 100644 (file)
@@ -328,13 +328,7 @@ int OpenDemux( vlc_object_t *p_this )
     free( psz_url );
 
     char *psz_opts = var_InheritString( p_demux, "avformat-options" );
-    const unsigned int nb_streams = p_sys->ic->nb_streams;
-    p_sys->tracks = calloc( nb_streams, sizeof(*p_sys->tracks) );
-    if( !p_sys->tracks )
-    {
-        CloseDemux( p_this );
-        return VLC_ENOMEM;
-    }
+    unsigned nb_streams = p_sys->ic->nb_streams;
 
     AVDictionary *options[nb_streams ? nb_streams : 1];
     options[0] = NULL;
@@ -349,7 +343,6 @@ int OpenDemux( vlc_object_t *p_this )
     }
     vlc_avcodec_lock(); /* avformat calls avcodec behind our back!!! */
     error = avformat_find_stream_info( p_sys->ic, options );
-    /* FIXME: what if nb_streams change after that call? */
     vlc_avcodec_unlock();
     AVDictionaryEntry *t = NULL;
     while ((t = av_dict_get(options[0], "", t, AV_DICT_IGNORE_SUFFIX))) {
@@ -360,6 +353,20 @@ int OpenDemux( vlc_object_t *p_this )
         av_dict_free(&options[i]);
     }
 
+    nb_streams = p_sys->ic->nb_streams; /* it may have changed */
+    if( !nb_streams )
+    {
+        msg_Err( p_demux, "No streams found");
+        CloseDemux( p_this );
+        return VLC_EGENERIC;
+    }
+    p_sys->tracks = calloc( nb_streams, sizeof(*p_sys->tracks) );
+    if( !p_sys->tracks )
+    {
+        CloseDemux( p_this );
+        return VLC_ENOMEM;
+    }
+
     if( error < 0 )
     {
         msg_Warn( p_demux, "Could not find stream info: %s",