PR #25470 opened by Kilian (lusoris)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25470
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25470.patch

This test-only patch addresses GCC 14.4.0 and 16.2.1 -Wstack-usage diagnostics 
against -Wstack-usage=122880 in libavcodec/tests/apv.c, 
libavcodec/tests/cabac.c and libavcodec/tests/snowenc.c.

What the patch does:

- `avcodec/tests: move large test buffers to the heap`: allocates large lookup 
tables and sample buffers on the heap, reports allocation failures and frees 
them on completion or error.

Behaviour change: test-only heap allocations add failure and cleanup paths; 
test inputs and comparisons are unchanged when allocation succeeds.

Base: FFmpeg master 46f23be8b1.

Testing:

- GCC 14.4.0 (`--enable-gpl --enable-vulkan`) and GCC 16.2.1 (`--enable-gpl 
--enable-vulkan --enable-vaapi --enable-libdrm --enable-nvenc`), targets all, 
alltools, examples, testprogs and checkasm: master 46f23be8b1 shows 4 
-Wstack-usage warnings in libavcodec/tests/apv.c, libavcodec/tests/cabac.c, 
libavcodec/tests/snowenc.c with each compiler; with this patch there are none 
and no new ones.
- FATE with GCC 16.2.1, `fate-cabac*`, `fate-apv*` and `fate-snow*` tests (6 
tests): the same results on master and with this patch; 3 fail on both sides 
only because their samples are missing from my local FATE sample copy, all 
others pass.

Split out of #25111 so that each part reaches the reviewers for its area.



>From 72349b6bd5a7f1997325482b25d94baa0599a5a2 Mon Sep 17 00:00:00 2001
From: lusoris <[email protected]>
Date: Thu, 15 Oct 2026 22:06:37 +0200
Subject: [PATCH] avcodec/tests: move large test buffers to the heap

GCC 14.4.0 and 16.2.1 report -Wstack-usage against FFmpeg's default
-Wstack-usage=122880 limit. Large lookup tables and sample buffers
increase stack requirements in the apv, cabac and snowenc tests.
Allocate these objects on the heap, report allocation failures and free
them on completion or error. With successful allocation, the test inputs
and comparisons are unchanged.

Signed-off-by: lusoris <[email protected]>
---
 libavcodec/tests/apv.c     | 54 +++++++++++++++++++++++++++-----------
 libavcodec/tests/cabac.c   | 14 ++++++++--
 libavcodec/tests/snowenc.c |  8 +++---
 3 files changed, 56 insertions(+), 20 deletions(-)

diff --git a/libavcodec/tests/apv.c b/libavcodec/tests/apv.c
index 365a395af1e..ca739c66c09 100644
--- a/libavcodec/tests/apv.c
+++ b/libavcodec/tests/apv.c
@@ -17,6 +17,7 @@
  */
 
 #include "libavutil/lfg.h"
+#include "libavutil/mem.h"
 #include "libavutil/random_seed.h"
 
 #include "libavcodec/apv_decode.h"
@@ -216,10 +217,15 @@ static void binary(char *buf, uint32_t value, int bits)
 
 static int test_apv_read_vlc(void)
 {
-    APVVLCLUT lut;
+    APVVLCLUT *lut = av_malloc(sizeof(*lut));
     int err = 0;
 
-    ff_apv_entropy_build_decode_lut(&lut);
+    if (!lut) {
+        av_log(NULL, AV_LOG_ERROR, "Unable to allocate APV VLC lookup 
table.\n");
+        return 1;
+    }
+
+    ff_apv_entropy_build_decode_lut(lut);
 
     // Generate all possible 20 bit sequences (padded with zeroes), then
     // verify that spec and improved parsing functions get the same result
@@ -241,7 +247,7 @@ static int test_apv_read_vlc(void)
             init_get_bits8(&gbc_test, buf, 8);
             init_get_bits8(&gbc_spec, buf, 8);
 
-            res_test = apv_read_vlc     (&gbc_test, k, &lut);
+            res_test = apv_read_vlc     (&gbc_test, k, lut);
             res_spec = apv_read_vlc_spec(&gbc_spec, k);
 
             con_test = get_bits_count(&gbc_test);
@@ -261,11 +267,13 @@ static int test_apv_read_vlc(void)
                        res_spec, con_spec);
                 ++err;
                 if (err > 10)
-                    return err;
+                    goto end;
             }
         }
     }
 
+end:
+    av_free(lut);
     return err;
 }
 
@@ -300,14 +308,21 @@ static int test_apv_entropy_decode_block(void)
     // Generate random entropy blocks, code them, then ensure they
     // decode to the same block with both implementations.
 
-    APVVLCLUT decode_lut;
+    APVVLCLUT *decode_lut = av_malloc(sizeof(*decode_lut));
     AVLFG lfg;
+    int result = 0;
     unsigned int seed = av_get_random_seed();
+
+    if (!decode_lut) {
+        av_log(NULL, AV_LOG_ERROR, "Unable to allocate APV VLC lookup 
table.\n");
+        return 1;
+    }
+
     av_lfg_init(&lfg, seed);
 
     av_log(NULL, AV_LOG_INFO, "seed = %u\n", seed);
 
-    ff_apv_entropy_build_decode_lut(&decode_lut);
+    ff_apv_entropy_build_decode_lut(decode_lut);
 
     for (int t = 0; t < 100; t++) {
         APVEntropyState state, save_state;
@@ -327,7 +342,7 @@ static int test_apv_entropy_decode_block(void)
 
         // Randomly-constructed state.
         memset(&state, 0, sizeof(state));
-        state.decode_lut   = &decode_lut;
+        state.decode_lut   = decode_lut;
         state.prev_dc      = random_coeff(&lfg);
         state.prev_k_dc    = av_lfg_get(&lfg) % 5;
         state.prev_k_level = av_lfg_get(&lfg) % 4;
@@ -372,13 +387,15 @@ static int test_apv_entropy_decode_block(void)
         err = apv_entropy_decode_block(block_test1, &gbc, &state);
         if (err < 0) {
             av_log(NULL, AV_LOG_ERROR, "Entropy decode returned error.\n");
-            return 1;
+            result = 1;
+            goto end;
         } else {
             int bits_read = get_bits_count(&gbc);
             if (bits_written != bits_read) {
                 av_log(NULL, AV_LOG_ERROR, "Wrote %d bits but read %d.\n",
                        bits_written, bits_read);
-                return 1;
+                result = 1;
+                goto end;
             } else {
                 err = 0;
                 for (int i = 0; i < 64; i++) {
@@ -387,7 +404,8 @@ static int test_apv_entropy_decode_block(void)
                 }
                 if (err > 0) {
                     av_log(NULL, AV_LOG_ERROR, "%d mismatches in output 
block.\n", err);
-                    return err;
+                    result = err;
+                    goto end;
                 }
             }
         }
@@ -398,13 +416,15 @@ static int test_apv_entropy_decode_block(void)
         err = ff_apv_entropy_decode_block(block_test2, &gbc, &save_state);
         if (err < 0) {
             av_log(NULL, AV_LOG_ERROR, "Entropy decode returned error.\n");
-            return 1;
+            result = 1;
+            goto end;
         } else {
             int bits_read = get_bits_count(&gbc);
             if (bits_written != bits_read) {
                 av_log(NULL, AV_LOG_ERROR, "Wrote %d bits but read %d.\n",
                        bits_written, bits_read);
-                return 1;
+                result = 1;
+                goto end;
             } else {
                 err = 0;
                 for (int i = 0; i < 64; i++) {
@@ -413,7 +433,8 @@ static int test_apv_entropy_decode_block(void)
                 }
                 if (err > 0) {
                     av_log(NULL, AV_LOG_ERROR, "%d mismatches in output 
block.\n", err);
-                    return err;
+                    result = err;
+                    goto end;
                 }
             }
         }
@@ -422,11 +443,14 @@ static int test_apv_entropy_decode_block(void)
             state.prev_k_dc    != save_state.prev_k_dc ||
             state.prev_k_level != save_state.prev_k_level) {
             av_log(NULL, AV_LOG_ERROR, "Entropy state mismatch.\n");
-            return 1;
+            result = 1;
+            goto end;
         }
     }
 
-    return 0;
+end:
+    av_free(decode_lut);
+    return result;
 }
 
 int main(void)
diff --git a/libavcodec/tests/cabac.c b/libavcodec/tests/cabac.c
index d9f98c68e08..7ff2e119ae6 100644
--- a/libavcodec/tests/cabac.c
+++ b/libavcodec/tests/cabac.c
@@ -24,6 +24,7 @@
 #define SIZE 10240
 
 #include "libavutil/lfg.h"
+#include "libavutil/mem.h"
 #include "libavcodec/put_bits.h"
 
 typedef struct CABACTestContext {
@@ -138,12 +139,19 @@ static void init_cabac_encoder(CABACTestContext *c, 
uint8_t *buf, int buf_size)
 
 int main(void){
     CABACTestContext c;
-    uint8_t b[9*SIZE];
-    uint8_t r[9*SIZE];
+    uint8_t *b = av_malloc(9 * SIZE);
+    uint8_t *r = av_malloc(9 * SIZE);
     int i, ret = 0;
     uint8_t state[10]= {0};
     AVLFG prng;
 
+    if (!b || !r) {
+        av_log(NULL, AV_LOG_ERROR, "Unable to allocate CABAC test buffers.\n");
+        av_free(b);
+        av_free(r);
+        return 1;
+    }
+
     av_lfg_init(&prng, 1);
     init_cabac_encoder(&c, b, SIZE);
 
@@ -186,5 +194,7 @@ int main(void){
         ret = 1;
     }
 
+    av_free(b);
+    av_free(r);
     return ret;
 }
diff --git a/libavcodec/tests/snowenc.c b/libavcodec/tests/snowenc.c
index 35feedba06e..7dd6caf438d 100644
--- a/libavcodec/tests/snowenc.c
+++ b/libavcodec/tests/snowenc.c
@@ -27,8 +27,8 @@
 int main(void){
 #define width  256
 #define height 256
-    int buffer[2][width*height];
-    short obuffer[width*height];
+    int (*buffer)[width * height] = av_malloc_array(2, sizeof(*buffer));
+    short *obuffer = av_malloc_array(width * height, sizeof(*obuffer));
     SnowContext s;
     int i;
     AVLFG prng;
@@ -39,7 +39,7 @@ int main(void){
     s.temp_dwt_buffer  = av_calloc(width, sizeof(*s.temp_dwt_buffer));
     s.temp_idwt_buffer = av_calloc(width, sizeof(*s.temp_idwt_buffer));
 
-    if (!s.temp_dwt_buffer || !s.temp_idwt_buffer) {
+    if (!buffer || !obuffer || !s.temp_dwt_buffer || !s.temp_idwt_buffer) {
         fprintf(stderr, "Failed to allocate memory\n");
         ret = 1;
         goto end;
@@ -144,6 +144,8 @@ int main(void){
     }
 
 end:
+    av_free(buffer);
+    av_free(obuffer);
     av_free(s.temp_dwt_buffer);
     av_free(s.temp_idwt_buffer);
     return ret;
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to