From 150c4e9edfde46d4bf03ebe043d13877b7248c96 Mon Sep 17 00:00:00 2001 From: Elimeshi1 Date: Wed, 15 Apr 2026 15:29:34 +0300 Subject: [PATCH] avformat/fifo: fix avf2->pb leak on avformat_write_header() failure When ff_format_output_open() succeeds avf2->pb (AVIOContext + buffer) is allocated. If the subsequent avformat_write_header() fails, ctx->header_written stays 0, so the cleanup path in fifo_thread_write_trailer() never calls ff_format_io_close(avf2, &avf2->pb). On the next recovery attempt ff_format_output_open() overwrites avf2->pb with a fresh allocation, making the old pointer permanently unreachable. With max_recovery_attempts=0 (unlimited retries) the leak is unbounded. Measured with rtmps:// output (~150 KB per AVIOContext + TLS session): 1 retry/2s over 9 hours = ~2.3 GB leaked -> OOM kill in production. Reproducer (triggers avformat_write_header failure on every attempt): ffmpeg -f lavfi -re -i testsrc=size=320x240:rate=25 \ -f lavfi -re -i sine=frequency=440:sample_rate=44100 \ -map 0:v -map 1:a -c:v flv -b:v 300k -c:a aac -b:a 64k \ -flags +global_header \ -f fifo -fifo_format flv \ -attempt_recovery 1 -recovery_wait_time 1 \ -max_recovery_attempts 0 -drop_pkts_on_overflow 1 \ /dev/full Without fix: VmRSS +820 KB/60s. With fix: VmRSS stable (<12 KB/60s). Fix: call ff_format_io_close(avf2, &avf2->pb) in the failure path so the AVIOContext is released before the next recovery attempt. Signed-off-by: Elimeshi1 --- libavformat/fifo.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libavformat/fifo.c b/libavformat/fifo.c index e66002b902..bb9c79e615 100644 --- a/libavformat/fifo.c +++ b/libavformat/fifo.c @@ -146,8 +146,11 @@ static int fifo_thread_write_header(FifoThreadContext *ctx) ffstream(avf2->streams[i])->cur_dts = 0; ret = avformat_write_header(avf2, &format_options); - if (!ret) + if (!ret) { ctx->header_written = 1; + } else { + ff_format_io_close(avf2, &avf2->pb); + } // Check for options unrecognized by underlying muxer if (format_options) {