From 87a7e7a3104394b30f47c5838e26654b168a55e1 Mon Sep 17 00:00:00 2001 From: p0her Date: Sat, 27 Jun 2026 21:00:10 +0900 Subject: [PATCH 1/2] Prevent stale APNG write row buffers across frames --- pngwutil.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pngwutil.c b/pngwutil.c index dae8850feb..823ee581fb 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -2886,6 +2886,21 @@ png_write_reset(png_struct *png_ptr) png_ptr->row_number = 0; png_ptr->pass = 0; png_ptr->mode &= ~PNG_HAVE_IDAT; + + /* APNG frames may have different dimensions, so the row and filter + * buffers are frame-local and must be recreated for each new frame. + */ + png_free(png_ptr, png_ptr->row_buf); + png_ptr->row_buf = NULL; + +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_free(png_ptr, png_ptr->prev_row); + png_free(png_ptr, png_ptr->try_row); + png_free(png_ptr, png_ptr->tst_row); + png_ptr->prev_row = NULL; + png_ptr->try_row = NULL; + png_ptr->tst_row = NULL; +#endif } void /* PRIVATE */ From bd0601a3b22abafdbb65273fddb3151331232d83 Mon Sep 17 00:00:00 2001 From: p0her Date: Sat, 27 Jun 2026 21:08:24 +0900 Subject: [PATCH 2/2] Keep APNG frame-size changes covered by tests Constraint: The row-buffer fix needs a stable APNG regression input that exercises frame dimension changes through pngtest. Rejected: Publishing a standalone exploit script | a small valid fixture integrated into existing tests is narrower. Confidence: high Scope-risk: narrow Directive: Preserve APNG frame-dimension regression coverage when changing writer buffer lifetime. Tested: ctest --test-dir build-asan -R '^pngtest-apng$' --output-on-failure; ctest --test-dir build-asan --output-on-failure -j2; srcdir=... tests/pngtest-all. Not-tested: APNG-disabled build configurations. --- CMakeLists.txt | 7 +++++++ contrib/testpngs/apng/frame-size-change.png | Bin 0 -> 290 bytes tests/pngtest-all | 3 +++ 3 files changed, 10 insertions(+) create mode 100644 contrib/testpngs/apng/frame-size-change.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 162d63a8d1..abaf0c7367 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -536,6 +536,8 @@ if(PNG_TESTS AND PNG_SHARED) list(SORT PNGSUITE_PNGS) file(GLOB TEST_PNGS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/testpngs/*.png") list(SORT TEST_PNGS) + file(GLOB TEST_APNG_PNGS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/testpngs/apng/*.png") + list(SORT TEST_APNG_PNGS) file(GLOB TEST_PNG3_PNGS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/testpngs/png-3/*.png") list(SORT TEST_PNG3_PNGS) @@ -555,6 +557,11 @@ if(PNG_TESTS AND PNG_SHARED) COMMAND pngtest FILES "${TEST_PNG3_PNGS}") + png_add_test(NAME pngtest-apng + COMMAND pngtest + OPTIONS --relaxed + FILES "${TEST_APNG_PNGS}") + # pnggetset test: # Getter-to-setter roundtrips for various chunk types. add_executable(pnggetset ${pnggetset_sources}) diff --git a/contrib/testpngs/apng/frame-size-change.png b/contrib/testpngs/apng/frame-size-change.png new file mode 100644 index 0000000000000000000000000000000000000000..06f03c17ca3648dc32ea647915a4c281eed466e2 GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nRj>O~;A0W*P#0=-&?m7UZq|zW_ zAR({@5CaSt8Gwep2)P5|NPD_ChE&W+p3pt(+kM;GclB(4KVAN>9HsY{oxyu5XQ}+2 zkOH7Gm|=`SHVlKbgLpv04)WY$0kQ?tQXE5oG!w|c{<(kU8JN#9i3=zjlmP`{Mu6Oi z#Xa*jKD7nP$U}`_0U8nD5%J-^arw`Bw!^np|6jc8-5+)aKSj>H8)H12fJzxWUHx3v IIVCg!0P>DNX8-^I literal 0 HcmV?d00001 diff --git a/tests/pngtest-all b/tests/pngtest-all index 6696ff52b7..418916504a 100755 --- a/tests/pngtest-all +++ b/tests/pngtest-all @@ -40,6 +40,9 @@ TEST --strict "${srcdir}"/pngtest.png # PNG-3 tests TEST --strict "${srcdir}"/contrib/testpngs/png-3/*.png +# APNG tests +TEST --relaxed "${srcdir}"/contrib/testpngs/apng/*.png + # Various crashers # Use --relaxed because some come from fuzzers that don't maintain CRCs TEST --relaxed "${srcdir}"/contrib/testpngs/crashers/badcrc.png