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.
This commit is contained in:
Stefano Sabatini 2011-12-20 13:08:57 +01:00
parent ab6603b1d8
commit 386aee6864
3 changed files with 76 additions and 11 deletions

View 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; \

View 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 */
/**

View 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,