Browse code

sink_buffer: copy list of provided formats in the context

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.

Stefano Sabatini authored on 2011/12/20 21:08:57
Showing 3 changed files
... ...
@@ -93,6 +93,32 @@ int ff_fmt_is_in(int fmt, const int *fmts)
93 93
     return 0;
94 94
 }
95 95
 
96
+#define COPY_INT_LIST(list_copy, list, type) {                          \
97
+    int count = 0;                                                      \
98
+    if (list)                                                           \
99
+        for (count = 0; list[count] != -1; count++)                     \
100
+            ;                                                           \
101
+    list_copy = av_calloc(count+1, sizeof(type));                       \
102
+    if (list_copy) {                                                    \
103
+        memcpy(list_copy, list, sizeof(type) * count);                  \
104
+        list_copy[count] = -1;                                          \
105
+    }                                                                   \
106
+}
107
+
108
+int *ff_copy_int_list(const int * const list)
109
+{
110
+    int *ret = NULL;
111
+    COPY_INT_LIST(ret, list, int);
112
+    return ret;
113
+}
114
+
115
+int64_t *ff_copy_int64_list(const int64_t * const list)
116
+{
117
+    int64_t *ret = NULL;
118
+    COPY_INT_LIST(ret, list, int64_t);
119
+    return ret;
120
+}
121
+
96 122
 #define MAKE_FORMAT_LIST()                                              \
97 123
     AVFilterFormats *formats;                                           \
98 124
     int count = 0;                                                      \
... ...
@@ -69,6 +69,18 @@ void ff_avfilter_default_free_buffer(AVFilterBuffer *buf);
69 69
 /** Tell is a format is contained in the provided list terminated by -1. */
70 70
 int ff_fmt_is_in(int fmt, const int *fmts);
71 71
 
72
+/**
73
+ * Return a copy of a list of integers terminated by -1, or NULL in
74
+ * case of copy failure.
75
+ */
76
+int *ff_copy_int_list(const int * const list);
77
+
78
+/**
79
+ * Return a copy of a list of 64-bit integers, or NULL in case of
80
+ * copy failure.
81
+ */
82
+int64_t *ff_copy_int64_list(const int64_t * const list);
83
+
72 84
 /* Functions to parse audio format arguments */
73 85
 
74 86
 /**
... ...
@@ -26,6 +26,7 @@
26 26
 #include "libavutil/fifo.h"
27 27
 #include "avfilter.h"
28 28
 #include "buffersink.h"
29
+#include "internal.h"
29 30
 
30 31
 AVBufferSinkParams *av_buffersink_params_alloc(void)
31 32
 {
... ...
@@ -58,12 +59,12 @@ typedef struct {
58 58
     AVFifoBuffer *fifo;                      ///< FIFO buffer of video frame references
59 59
 
60 60
     /* only used for video */
61
-    const enum PixelFormat *pixel_fmts;     ///< list of accepted pixel formats, must be terminated with -1
61
+    enum PixelFormat *pixel_fmts;           ///< list of accepted pixel formats, must be terminated with -1
62 62
 
63 63
     /* only used for audio */
64
-    const enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
65
-    const int64_t *channel_layouts;         ///< list of accepted channel layouts, terminated by -1
66
-    const int *packing_fmts;                ///< list of accepted packing formats, terminated by -1
64
+    enum AVSampleFormat *sample_fmts;       ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
65
+    int64_t *channel_layouts;               ///< list of accepted channel layouts, terminated by -1
66
+    int *packing_fmts;                      ///< list of accepted packing formats, terminated by -1
67 67
 } BufferSinkContext;
68 68
 
69 69
 #define FIFO_INIT_SIZE 8
... ...
@@ -169,16 +170,26 @@ static av_cold int vsink_init(AVFilterContext *ctx, const char *args, void *opaq
169 169
         return AVERROR(EINVAL);
170 170
     } else {
171 171
 #if FF_API_OLD_VSINK_API
172
-        buf->pixel_fmts = (const enum PixelFormat *)opaque;
172
+        const int *pixel_fmts = (const enum PixelFormat *)opaque;
173 173
 #else
174 174
         params = (AVBufferSinkParams *)opaque;
175
-        buf->pixel_fmts = params->pixel_fmts;
175
+        const int *pixel_fmts = params->pixel_fmts;
176 176
 #endif
177
+        buf->pixel_fmts = ff_copy_int_list(pixel_fmts);
178
+        if (!buf->pixel_fmts)
179
+            return AVERROR(ENOMEM);
177 180
     }
178 181
 
179 182
     return common_init(ctx);
180 183
 }
181 184
 
185
+static av_cold void vsink_uninit(AVFilterContext *ctx)
186
+{
187
+    BufferSinkContext *buf = ctx->priv;
188
+    av_freep(&buf->pixel_fmts);
189
+    return common_uninit(ctx);
190
+}
191
+
182 192
 static int vsink_query_formats(AVFilterContext *ctx)
183 193
 {
184 194
     BufferSinkContext *buf = ctx->priv;
... ...
@@ -192,7 +203,7 @@ AVFilter avfilter_vsink_buffersink = {
192 192
     .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
193 193
     .priv_size = sizeof(BufferSinkContext),
194 194
     .init      = vsink_init,
195
-    .uninit    = common_uninit,
195
+    .uninit    = vsink_uninit,
196 196
 
197 197
     .query_formats = vsink_query_formats,
198 198
 
... ...
@@ -225,13 +236,29 @@ static av_cold int asink_init(AVFilterContext *ctx, const char *args, void *opaq
225 225
     } else
226 226
         params = (AVABufferSinkParams *)opaque;
227 227
 
228
-    buf->sample_fmts     = params->sample_fmts;
229
-    buf->channel_layouts = params->channel_layouts;
230
-    buf->packing_fmts    = params->packing_fmts;
228
+    buf->sample_fmts     = ff_copy_int_list  (params->sample_fmts);
229
+    buf->channel_layouts = ff_copy_int64_list(params->channel_layouts);
230
+    buf->packing_fmts    = ff_copy_int_list  (params->packing_fmts);
231
+    if (!buf->sample_fmts || !buf->channel_layouts || !buf->sample_fmts) {
232
+        av_freep(&buf->sample_fmts);
233
+        av_freep(&buf->channel_layouts);
234
+        av_freep(&buf->packing_fmts);
235
+        return AVERROR(ENOMEM);
236
+    }
231 237
 
232 238
     return common_init(ctx);
233 239
 }
234 240
 
241
+static av_cold void asink_uninit(AVFilterContext *ctx)
242
+{
243
+    BufferSinkContext *buf = ctx->priv;
244
+
245
+    av_freep(&buf->sample_fmts);
246
+    av_freep(&buf->channel_layouts);
247
+    av_freep(&buf->packing_fmts);
248
+    return common_uninit(ctx);
249
+}
250
+
235 251
 static int asink_query_formats(AVFilterContext *ctx)
236 252
 {
237 253
     BufferSinkContext *buf = ctx->priv;
... ...
@@ -256,7 +283,7 @@ AVFilter avfilter_asink_abuffersink = {
256 256
     .name      = "abuffersink",
257 257
     .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
258 258
     .init      = asink_init,
259
-    .uninit    = common_uninit,
259
+    .uninit    = asink_uninit,
260 260
     .priv_size = sizeof(BufferSinkContext),
261 261
     .query_formats = asink_query_formats,
262 262