tests/fate/libavutil: add FATE test for buffer

Test av_buffer_alloc, av_buffer_allocz, av_buffer_create with
custom free callback, AV_BUFFER_FLAG_READONLY, av_buffer_ref,
av_buffer_is_writable, av_buffer_get_ref_count,
av_buffer_make_writable, av_buffer_realloc (including from NULL),
av_buffer_replace (including with NULL), av_buffer_pool
init/get/uninit cycle, av_buffer_pool_init2 with custom alloc
and pool_free callbacks, av_buffer_pool_buffer_get_opaque, and
OOM paths via av_max_alloc.

Coverage for libavutil/buffer.c: 0.00% -> 90.19%

Remaining uncovered lines are mutex init failures and
secondary allocation failure paths.
This commit is contained in:
marcos ashton
2026-04-09 15:24:48 +01:00
committed by michaelni
parent 03931e8865
commit 2d9c8a9382
5 changed files with 315 additions and 0 deletions
+2
View File
@@ -232,7 +232,9 @@ doc/.* @GyanD
# tests
# =====
tests/checkasm/riscv/.* @Courmisch
libavutil/tests/buffer.* @MarcosAsh
tests/ref/.*drawvg.* @ayosec
tests/ref/fate/buffer @MarcosAsh
tests/ref/fate/sub-mcc.* @programmerjake
# Forgejo
+1
View File
@@ -263,6 +263,7 @@ TESTPROGS = adler32 \
base64 \
blowfish \
bprint \
buffer \
cast5 \
camellia \
channel_layout \
+251
View File
@@ -0,0 +1,251 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "libavutil/buffer.h"
#include "libavutil/mem.h"
static int custom_free_called;
static int pool_free_called;
static int pool_alloc2_called;
static void custom_free(void *opaque, uint8_t *data)
{
custom_free_called = 1;
av_free(data);
}
static AVBufferRef *pool_alloc2(void *opaque, size_t size)
{
pool_alloc2_called = 1;
return av_buffer_alloc(size);
}
static void pool_free_cb(void *opaque)
{
pool_free_called = 1;
}
int main(void)
{
AVBufferRef *buf, *buf2;
AVBufferPool *pool;
/* av_buffer_alloc */
printf("Testing av_buffer_alloc()\n");
buf = av_buffer_alloc(64);
if (buf) {
printf("alloc: size=%zu data=%s\n", buf->size, buf->data ? "set" : "null");
printf("writable: %d\n", av_buffer_is_writable(buf));
printf("refcount: %d\n", av_buffer_get_ref_count(buf));
av_buffer_unref(&buf);
printf("after unref: %s\n", buf == NULL ? "null" : "leaked");
}
/* av_buffer_allocz */
printf("\nTesting av_buffer_allocz()\n");
buf = av_buffer_allocz(16);
if (buf) {
int zeroed = 1;
for (int i = 0; i < 16; i++)
if (buf->data[i] != 0) zeroed = 0;
printf("allocz: zeroed=%s\n", zeroed ? "yes" : "no");
av_buffer_unref(&buf);
}
/* av_buffer_create with custom free */
printf("\nTesting av_buffer_create()\n");
{
uint8_t *data = av_malloc(32);
if (data) {
custom_free_called = 0;
buf = av_buffer_create(data, 32, custom_free, NULL, 0);
if (buf) {
printf("create: size=%zu\n", buf->size);
printf("opaque: %s\n",
av_buffer_get_opaque(buf) == NULL ? "null" : "set");
av_buffer_unref(&buf);
printf("custom_free called: %s\n",
custom_free_called ? "yes" : "no");
} else {
av_free(data);
}
}
}
/* av_buffer_create with READONLY flag */
printf("\nTesting AV_BUFFER_FLAG_READONLY\n");
{
uint8_t *data = av_malloc(16);
if (data) {
buf = av_buffer_create(data, 16, custom_free, NULL,
AV_BUFFER_FLAG_READONLY);
if (buf) {
printf("readonly writable: %d\n", av_buffer_is_writable(buf));
av_buffer_unref(&buf);
} else {
av_free(data);
}
}
}
/* av_buffer_ref and refcounting */
printf("\nTesting av_buffer_ref()\n");
buf = av_buffer_alloc(32);
if (buf) {
buf->data[0] = 0xAB;
buf2 = av_buffer_ref(buf);
if (buf2) {
printf("ref: refcount=%d\n", av_buffer_get_ref_count(buf));
printf("shared data: %s\n",
buf2->data[0] == 0xAB ? "yes" : "no");
printf("writable after ref: %d\n", av_buffer_is_writable(buf));
av_buffer_unref(&buf2);
printf("refcount after unref: %d\n", av_buffer_get_ref_count(buf));
printf("writable after unref: %d\n", av_buffer_is_writable(buf));
}
av_buffer_unref(&buf);
}
/* av_buffer_make_writable */
printf("\nTesting av_buffer_make_writable()\n");
buf = av_buffer_alloc(16);
if (buf) {
buf->data[0] = 0xCD;
buf2 = av_buffer_ref(buf);
if (buf2) {
int ret = av_buffer_make_writable(&buf2);
printf("make_writable ret: %d\n", ret >= 0);
printf("data preserved: %s\n",
buf2->data[0] == 0xCD ? "yes" : "no");
printf("now writable: %d\n", av_buffer_is_writable(buf2));
printf("original still valid: %s\n",
buf->data[0] == 0xCD ? "yes" : "no");
av_buffer_unref(&buf2);
}
av_buffer_unref(&buf);
}
/* av_buffer_realloc */
printf("\nTesting av_buffer_realloc()\n");
buf = av_buffer_alloc(16);
if (buf) {
memset(buf->data, 0xEF, 16);
av_buffer_realloc(&buf, 32);
if (buf) {
printf("realloc: size=%zu\n", buf->size);
printf("data preserved: %s\n",
buf->data[0] == 0xEF ? "yes" : "no");
}
av_buffer_unref(&buf);
}
/* realloc from NULL */
buf = NULL;
av_buffer_realloc(&buf, 8);
printf("realloc from null: %s\n", buf ? "OK" : "FAIL");
av_buffer_unref(&buf);
/* av_buffer_replace */
printf("\nTesting av_buffer_replace()\n");
buf = av_buffer_alloc(8);
buf2 = av_buffer_alloc(8);
if (buf && buf2) {
buf->data[0] = 0x11;
buf2->data[0] = 0x22;
av_buffer_replace(&buf, buf2);
printf("replace: data=0x%02x\n", buf->data[0]);
printf("refcount: %d\n", av_buffer_get_ref_count(buf2));
}
av_buffer_unref(&buf);
av_buffer_unref(&buf2);
/* replace with NULL */
buf = av_buffer_alloc(8);
if (buf) {
av_buffer_replace(&buf, NULL);
printf("replace with null: %s\n", buf == NULL ? "OK" : "FAIL");
}
/* av_buffer_pool */
printf("\nTesting av_buffer_pool()\n");
pool = av_buffer_pool_init(64, NULL);
if (pool) {
buf = av_buffer_pool_get(pool);
if (buf) {
printf("pool get: size=%zu\n", buf->size);
av_buffer_unref(&buf);
}
/* get again -- should reuse the released buffer */
buf = av_buffer_pool_get(pool);
if (buf) {
printf("pool reuse: size=%zu\n", buf->size);
av_buffer_unref(&buf);
}
av_buffer_pool_uninit(&pool);
printf("pool uninit: %s\n", pool == NULL ? "OK" : "FAIL");
}
/* av_buffer_pool_init2 with custom alloc and pool_free callbacks */
printf("\nTesting av_buffer_pool_init2()\n");
pool_alloc2_called = 0;
pool_free_called = 0;
pool = av_buffer_pool_init2(64, NULL, pool_alloc2, pool_free_cb);
if (pool) {
buf = av_buffer_pool_get(pool);
if (buf) {
printf("pool2 get: size=%zu\n", buf->size);
printf("alloc2 called: %s\n", pool_alloc2_called ? "yes" : "no");
printf("pool_buffer_get_opaque: %s\n",
av_buffer_pool_buffer_get_opaque(buf) == NULL ? "null" : "set");
av_buffer_unref(&buf);
}
av_buffer_pool_uninit(&pool);
printf("pool_free called: %s\n", pool_free_called ? "yes" : "no");
}
/* OOM paths via av_max_alloc */
printf("\nTesting OOM paths\n");
av_max_alloc(1);
buf = av_buffer_alloc(64);
printf("alloc OOM: %s\n", buf ? "FAIL" : "OK");
av_buffer_unref(&buf);
buf = av_buffer_allocz(64);
printf("allocz OOM: %s\n", buf ? "FAIL" : "OK");
av_buffer_unref(&buf);
pool = av_buffer_pool_init(64, NULL);
printf("pool init OOM: %s\n", pool ? "FAIL" : "OK");
av_buffer_pool_uninit(&pool);
av_max_alloc(INT_MAX);
buf = av_buffer_alloc(16);
if (buf) {
av_max_alloc(1);
buf2 = av_buffer_ref(buf);
printf("ref OOM: %s\n", buf2 ? "FAIL" : "OK");
av_buffer_unref(&buf2);
printf("realloc OOM: %s\n",
av_buffer_realloc(&buf, 1024) < 0 ? "OK" : "FAIL");
av_max_alloc(INT_MAX);
av_buffer_unref(&buf);
}
return 0;
}
+4
View File
@@ -47,6 +47,10 @@ FATE_LIBAVUTIL += fate-bprint
fate-bprint: libavutil/tests/bprint$(EXESUF)
fate-bprint: CMD = run libavutil/tests/bprint$(EXESUF)
FATE_LIBAVUTIL += fate-buffer
fate-buffer: libavutil/tests/buffer$(EXESUF)
fate-buffer: CMD = run libavutil/tests/buffer$(EXESUF)
FATE_LIBAVUTIL += fate-cpu
fate-cpu: libavutil/tests/cpu$(EXESUF)
fate-cpu: CMD = runecho libavutil/tests/cpu$(EXESUF) $(CPUFLAGS:%=-c%) $(THREADS:%=-t%)
+57
View File
@@ -0,0 +1,57 @@
Testing av_buffer_alloc()
alloc: size=64 data=set
writable: 1
refcount: 1
after unref: null
Testing av_buffer_allocz()
allocz: zeroed=yes
Testing av_buffer_create()
create: size=32
opaque: null
custom_free called: yes
Testing AV_BUFFER_FLAG_READONLY
readonly writable: 0
Testing av_buffer_ref()
ref: refcount=2
shared data: yes
writable after ref: 0
refcount after unref: 1
writable after unref: 1
Testing av_buffer_make_writable()
make_writable ret: 1
data preserved: yes
now writable: 1
original still valid: yes
Testing av_buffer_realloc()
realloc: size=32
data preserved: yes
realloc from null: OK
Testing av_buffer_replace()
replace: data=0x22
refcount: 2
replace with null: OK
Testing av_buffer_pool()
pool get: size=64
pool reuse: size=64
pool uninit: OK
Testing av_buffer_pool_init2()
pool2 get: size=64
alloc2 called: yes
pool_buffer_get_opaque: null
pool_free called: yes
Testing OOM paths
alloc OOM: OK
allocz OOM: OK
pool init OOM: OK
ref OOM: OK
realloc OOM: OK