summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Rheinhardt <andreas.rheinhardt@outlook.com>2021-09-14 11:29:23 +0200
committerAndreas Rheinhardt <andreas.rheinhardt@outlook.com>2021-09-18 23:16:49 +0200
commit4e0da7d3117bbf84203358940cba82ef10b6dfde (patch)
treee615af324744e7fe5df30a0e3974324a2d785246
parent6556146aa0c21c32981405b45bb7eea7376e54c9 (diff)
avutil/buffer: Avoid allocation of AVBuffer when using buffer pool
Do this by putting an AVBuffer structure into BufferPoolEntry and reuse it for all subsequent uses of said BufferPoolEntry. Reviewed-by: James Almer <jamrial@gmail.com> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
-rw-r--r--libavutil/buffer.c44
-rw-r--r--libavutil/buffer_internal.h11
2 files changed, 41 insertions, 14 deletions
diff --git a/libavutil/buffer.c b/libavutil/buffer.c
index a32b7deb89..54590be566 100644
--- a/libavutil/buffer.c
+++ b/libavutil/buffer.c
@@ -26,16 +26,11 @@
#include "mem.h"
#include "thread.h"
-AVBufferRef *av_buffer_create(uint8_t *data, size_t size,
- void (*free)(void *opaque, uint8_t *data),
- void *opaque, int flags)
+static AVBufferRef *buffer_create(AVBuffer *buf, uint8_t *data, size_t size,
+ void (*free)(void *opaque, uint8_t *data),
+ void *opaque, int flags)
{
AVBufferRef *ref = NULL;
- AVBuffer *buf = NULL;
-
- buf = av_mallocz(sizeof(*buf));
- if (!buf)
- return NULL;
buf->data = data;
buf->size = size;
@@ -47,10 +42,8 @@ AVBufferRef *av_buffer_create(uint8_t *data, size_t size,
buf->flags = flags;
ref = av_mallocz(sizeof(*ref));
- if (!ref) {
- av_freep(&buf);
+ if (!ref)
return NULL;
- }
ref->buffer = buf;
ref->data = data;
@@ -59,6 +52,23 @@ AVBufferRef *av_buffer_create(uint8_t *data, size_t size,
return ref;
}
+AVBufferRef *av_buffer_create(uint8_t *data, size_t size,
+ void (*free)(void *opaque, uint8_t *data),
+ void *opaque, int flags)
+{
+ AVBufferRef *ret;
+ AVBuffer *buf = av_mallocz(sizeof(*buf));
+ if (!buf)
+ return NULL;
+
+ ret = buffer_create(buf, data, size, free, opaque, flags);
+ if (!ret) {
+ av_free(buf);
+ return NULL;
+ }
+ return ret;
+}
+
void av_buffer_default_free(void *opaque, uint8_t *data)
{
av_free(data);
@@ -117,8 +127,12 @@ static void buffer_replace(AVBufferRef **dst, AVBufferRef **src)
av_freep(dst);
if (atomic_fetch_sub_explicit(&b->refcount, 1, memory_order_acq_rel) == 1) {
+ /* b->free below might already free the structure containing *b,
+ * so we have to read the flag now to avoid use-after-free. */
+ int free_avbuffer = !(b->flags_internal & BUFFER_FLAG_NO_FREE);
b->free(b->opaque, b->data);
- av_freep(&b);
+ if (free_avbuffer)
+ av_free(b);
}
}
@@ -378,11 +392,13 @@ AVBufferRef *av_buffer_pool_get(AVBufferPool *pool)
ff_mutex_lock(&pool->mutex);
buf = pool->pool;
if (buf) {
- ret = av_buffer_create(buf->data, pool->size, pool_release_buffer,
- buf, 0);
+ memset(&buf->buffer, 0, sizeof(buf->buffer));
+ ret = buffer_create(&buf->buffer, buf->data, pool->size,
+ pool_release_buffer, buf, 0);
if (ret) {
pool->pool = buf->next;
buf->next = NULL;
+ buf->buffer.flags_internal |= BUFFER_FLAG_NO_FREE;
}
} else {
ret = pool_alloc_buffer(pool);
diff --git a/libavutil/buffer_internal.h b/libavutil/buffer_internal.h
index 839dc05f8f..bdff1b5b32 100644
--- a/libavutil/buffer_internal.h
+++ b/libavutil/buffer_internal.h
@@ -30,6 +30,11 @@
* The buffer was av_realloc()ed, so it is reallocatable.
*/
#define BUFFER_FLAG_REALLOCATABLE (1 << 0)
+/**
+ * The AVBuffer structure is part of a larger structure
+ * and should not be freed.
+ */
+#define BUFFER_FLAG_NO_FREE (1 << 1)
struct AVBuffer {
uint8_t *data; /**< data described by this buffer */
@@ -73,6 +78,12 @@ typedef struct BufferPoolEntry {
AVBufferPool *pool;
struct BufferPoolEntry *next;
+
+ /*
+ * An AVBuffer structure to (re)use as AVBuffer for subsequent uses
+ * of this BufferPoolEntry.
+ */
+ AVBuffer buffer;
} BufferPoolEntry;
struct AVBufferPool {