PR #22821 opened by elimeshi
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22821
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22821.patch
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 <[email protected]>
>From 935eec6ed27d11195039a8145ac96d2a14d60fdc Mon Sep 17 00:00:00 2001
From: Elimeshi1 <[email protected]>
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 <[email protected]>
---
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) {
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]