diff mbox series

[FFmpeg-devel,6/9] avformat/rmdec: Fix memleaks upon read_header failure

Message ID 20200721021215.32647-4-andreas.rheinhardt@gmail.com
State Superseded
Headers show
Series [FFmpeg-devel,v2,1/2] avformat: Redo cleanup of demuxer upon read_header() failure | expand

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Andreas Rheinhardt July 21, 2020, 2:12 a.m. UTC
For both the RealMedia as well as the IVR demuxer (which share the same
context) each AVStream's priv_data contains an AVPacket that might
contain data (even when reading the header) and therefore needs to be
unreferenced. Up until now, this has not always been done:

The RealMedia demuxer didn't do it when allocating a new stream's
priv_data failed although there might other streams with packets to
unreference. (The reason for this was that until recently rm_read_close()
couldn't handle an AVStream without priv_data, so one had to choose
between a potential crash and a memleak.)

The IVR demuxer meanwhile never ever called read_close so that the data
already contained in packets leaks upon error.

This patch fixes both demuxers by setting the AVFMT_HEADER_CLEANUP flag,
thereby ensuring that rm_read_close() is always called when reading the
header fails. This also allows to remove several "goto fail" in
rm_read_header().

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
---
 libavformat/rmdec.c | 20 +++++++-------------
 1 file changed, 7 insertions(+), 13 deletions(-)
diff mbox series

Patch

diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c
index 72b8dba741..c88f41c121 100644
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -66,8 +66,6 @@  typedef struct RMDemuxContext {
     int data_end;
 } RMDemuxContext;
 
-static int rm_read_close(AVFormatContext *s);
-
 static inline void get_strl(AVIOContext *pb, char *buf, int buf_size, int len)
 {
     int read = avio_get_str(pb, len, buf, buf_size);
@@ -557,16 +555,15 @@  static int rm_read_header(AVFormatContext *s)
     avio_skip(pb, tag_size - 8);
 
     for(;;) {
-        ret = AVERROR_INVALIDDATA;
         if (avio_feof(pb))
-            goto fail;
+            return AVERROR_INVALIDDATA;
         tag = avio_rl32(pb);
         tag_size = avio_rb32(pb);
         avio_rb16(pb);
         av_log(s, AV_LOG_TRACE, "tag=%s size=%d\n",
                av_fourcc2str(tag), tag_size);
         if (tag_size < 10 && tag != MKTAG('D', 'A', 'T', 'A'))
-            goto fail;
+            return AVERROR_INVALIDDATA;
         switch(tag) {
         case MKTAG('P', 'R', 'O', 'P'):
             /* file header */
@@ -589,8 +586,7 @@  static int rm_read_header(AVFormatContext *s)
         case MKTAG('M', 'D', 'P', 'R'):
             st = avformat_new_stream(s, NULL);
             if (!st) {
-                ret = AVERROR(ENOMEM);
-                goto fail;
+                return AVERROR(ENOMEM);
             }
             st->id = avio_rb16(pb);
             avio_rb32(pb); /* max bit rate */
@@ -619,14 +615,14 @@  static int rm_read_header(AVFormatContext *s)
             if (v == MKBETAG('M', 'L', 'T', 'I')) {
                 ret = rm_read_multi(s, s->pb, st, mime);
                 if (ret < 0)
-                    goto fail;
+                    return ret;
                 avio_seek(pb, codec_pos + size, SEEK_SET);
             } else {
                 avio_skip(pb, -4);
                 ret = ff_rm_read_mdpr_codecdata(s, s->pb, st, st->priv_data,
                                                 size, mime);
                 if (ret < 0)
-                    goto fail;
+                    return ret;
             }
 
             break;
@@ -654,10 +650,6 @@  static int rm_read_header(AVFormatContext *s)
     }
 
     return 0;
-
-fail:
-    rm_read_close(s);
-    return ret;
 }
 
 static int get_num(AVIOContext *pb, int *len)
@@ -1141,6 +1133,7 @@  static int rm_read_seek(AVFormatContext *s, int stream_index,
 AVInputFormat ff_rm_demuxer = {
     .name           = "rm",
     .long_name      = NULL_IF_CONFIG_SMALL("RealMedia"),
+    .flags          = AVFMT_HEADER_CLEANUP,
     .priv_data_size = sizeof(RMDemuxContext),
     .read_probe     = rm_probe,
     .read_header    = rm_read_header,
@@ -1393,6 +1386,7 @@  static int ivr_read_packet(AVFormatContext *s, AVPacket *pkt)
 AVInputFormat ff_ivr_demuxer = {
     .name           = "ivr",
     .long_name      = NULL_IF_CONFIG_SMALL("IVR (Internet Video Recording)"),
+    .flags          = AVFMT_HEADER_CLEANUP,
     .priv_data_size = sizeof(RMDemuxContext),
     .read_probe     = ivr_probe,
     .read_header    = ivr_read_header,