sink_buffer: copy list of provided formats in the context
authorStefano Sabatini <stefasab@gmail.com>
Tue, 20 Dec 2011 12:08:57 +0000 (13:08 +0100)
committerStefano Sabatini <stefasab@gmail.com>
Thu, 22 Dec 2011 09:09:42 +0000 (10:09 +0100)
A list of formats may have been dynamically created by the calling code,
and thus should not be referenced by the sink buffer context.

Avoid possible invalid data reference.

libavfilter/formats.c
libavfilter/internal.h
libavfilter/sink_buffer.c

index ff4d49d..fa2c1be 100644 (file)
@@ -93,6 +93,32 @@ int ff_fmt_is_in(int fmt, const int *fmts)
     return 0;
 }
 
+#define COPY_INT_LIST(list_copy, list, type) {                          \
+    int count = 0;                                                      \
+    if (list)                                                           \
+        for (count = 0; list[count] != -1; count++)                     \
+            ;                                                           \
+    list_copy = av_calloc(count+1, sizeof(type));                       \
+    if (list_copy) {                                                    \
+        memcpy(list_copy, list, sizeof(type) * count);                  \
+        list_copy[count] = -1;                                          \
+    }                                                                   \
+}
+
+int *ff_copy_int_list(const int * const list)
+{
+    int *ret = NULL;
+    COPY_INT_LIST(ret, list, int);
+    return ret;
+}
+
+int64_t *ff_copy_int64_list(const int64_t * const list)
+{
+    int64_t *ret = NULL;
+    COPY_INT_LIST(ret, list, int64_t);
+    return ret;
+}
+
 #define MAKE_FORMAT_LIST()                                              \
     AVFilterFormats *formats;                                           \
     int count = 0;                                                      \
index 9f28a83..227fe62 100644 (file)
@@ -69,6 +69,18 @@ void ff_avfilter_default_free_buffer(AVFilterBuffer *buf);
 /** Tell is a format is contained in the provided list terminated by -1. */
 int ff_fmt_is_in(int fmt, const int *fmts);
 
+/**
+ * Return a copy of a list of integers terminated by -1, or NULL in
+ * case of copy failure.
+ */
+int *ff_copy_int_list(const int * const list);
+
+/**
+ * Return a copy of a list of 64-bit integers, or NULL in case of
+ * copy failure.
+ */
+int64_t *ff_copy_int64_list(const int64_t * const list);
+
 /* Functions to parse audio format arguments */
 
 /**
index e572385..926362b 100644 (file)
@@ -26,6 +26,7 @@
 #include "libavutil/fifo.h"
 #include "avfilter.h"
 #include "buffersink.h"
+#include "internal.h"
 
 AVBufferSinkParams *av_buffersink_params_alloc(void)
 {
@@ -58,12 +59,12 @@ typedef struct {
     AVFifoBuffer *fifo;                      ///< FIFO buffer of video frame references
 
     /* only used for video */
-    const enum PixelFormat *pixel_fmts;     ///< list of accepted pixel formats, must be terminated with -1
+    enum PixelFormat *pixel_fmts;           ///< list of accepted pixel formats, must be terminated with -1
 
     /* only used for audio */
-    const enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
-    const int64_t *channel_layouts;         ///< list of accepted channel layouts, terminated by -1
-    const int *packing_fmts;                ///< list of accepted packing formats, terminated by -1
+    enum AVSampleFormat *sample_fmts;       ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
+    int64_t *channel_layouts;               ///< list of accepted channel layouts, terminated by -1
+    int *packing_fmts;                      ///< list of accepted packing formats, terminated by -1
 } BufferSinkContext;
 
 #define FIFO_INIT_SIZE 8
@@ -169,16 +170,26 @@ static av_cold int vsink_init(AVFilterContext *ctx, const char *args, void *opaq
         return AVERROR(EINVAL);
     } else {
 #if FF_API_OLD_VSINK_API
-        buf->pixel_fmts = (const enum PixelFormat *)opaque;
+        const int *pixel_fmts = (const enum PixelFormat *)opaque;
 #else
         params = (AVBufferSinkParams *)opaque;
-        buf->pixel_fmts = params->pixel_fmts;
+        const int *pixel_fmts = params->pixel_fmts;
 #endif
+        buf->pixel_fmts = ff_copy_int_list(pixel_fmts);
+        if (!buf->pixel_fmts)
+            return AVERROR(ENOMEM);
     }
 
     return common_init(ctx);
 }
 
+static av_cold void vsink_uninit(AVFilterContext *ctx)
+{
+    BufferSinkContext *buf = ctx->priv;
+    av_freep(&buf->pixel_fmts);
+    return common_uninit(ctx);
+}
+
 static int vsink_query_formats(AVFilterContext *ctx)
 {
     BufferSinkContext *buf = ctx->priv;
@@ -192,7 +203,7 @@ AVFilter avfilter_vsink_buffersink = {
     .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
     .priv_size = sizeof(BufferSinkContext),
     .init      = vsink_init,
-    .uninit    = common_uninit,
+    .uninit    = vsink_uninit,
 
     .query_formats = vsink_query_formats,
 
@@ -225,13 +236,29 @@ static av_cold int asink_init(AVFilterContext *ctx, const char *args, void *opaq
     } else
         params = (AVABufferSinkParams *)opaque;
 
-    buf->sample_fmts     = params->sample_fmts;
-    buf->channel_layouts = params->channel_layouts;
-    buf->packing_fmts    = params->packing_fmts;
+    buf->sample_fmts     = ff_copy_int_list  (params->sample_fmts);
+    buf->channel_layouts = ff_copy_int64_list(params->channel_layouts);
+    buf->packing_fmts    = ff_copy_int_list  (params->packing_fmts);
+    if (!buf->sample_fmts || !buf->channel_layouts || !buf->sample_fmts) {
+        av_freep(&buf->sample_fmts);
+        av_freep(&buf->channel_layouts);
+        av_freep(&buf->packing_fmts);
+        return AVERROR(ENOMEM);
+    }
 
     return common_init(ctx);
 }
 
+static av_cold void asink_uninit(AVFilterContext *ctx)
+{
+    BufferSinkContext *buf = ctx->priv;
+
+    av_freep(&buf->sample_fmts);
+    av_freep(&buf->channel_layouts);
+    av_freep(&buf->packing_fmts);
+    return common_uninit(ctx);
+}
+
 static int asink_query_formats(AVFilterContext *ctx)
 {
     BufferSinkContext *buf = ctx->priv;
@@ -256,7 +283,7 @@ AVFilter avfilter_asink_abuffersink = {
     .name      = "abuffersink",
     .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
     .init      = asink_init,
-    .uninit    = common_uninit,
+    .uninit    = asink_uninit,
     .priv_size = sizeof(BufferSinkContext),
     .query_formats = asink_query_formats,