Merge tag 'v1.6.57' into branch 'libpng18' into develop
diff --git a/AUTHORS.md b/AUTHORS.md
index 3c924f9..291a0b7 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -29,6 +29,7 @@
  * Mans Rullgard
  * Matt Sarett
  * Mike Klein
+ * Mohammad Seet
  * Pascal Massimino
  * Paul Schmidt
  * Petr Simecek
diff --git a/CHANGES b/CHANGES
index cdcc35c..7a6156e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -6368,6 +6368,17 @@
     (Contributed by Bob Friesenhahn and Philippe Antoine.)
   Performed various refactorings and cleanups.
 
+Version 1.6.57 [April 8, 2026]
+  Fixed CVE-2026-34757 (medium severity):
+    Use-after-free in `png_set_PLTE`, `png_set_tRNS` and `png_set_hIST`
+    leading to corrupted chunk data and potential heap information disclosure.
+    Also hardened the append-style setters (`png_set_text`, `png_set_sPLT`,
+    `png_set_unknown_chunks`) against a theoretical variant of the same
+    aliasing pattern.
+    (Reported by Iv4n <Iv4n550@users.noreply.github.com>.)
+  Fixed integer overflow in rowbytes computation in read transforms.
+    (Contributed by Mohammad Seet.)
+
 Version 2.0.0 [TODO]
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1890e8c..8e92b6f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -387,6 +387,9 @@
 set(pngstest_sources
     contrib/libtests/pngstest.c
 )
+set(pnggetset_sources
+    contrib/libtests/pnggetset.c
+)
 set(pngunknown_sources
     contrib/libtests/pngunknown.c
 )
@@ -549,6 +552,15 @@
                COMMAND pngtest
                FILES "${TEST_PNG3_PNGS}")
 
+  # pnggetset test:
+  # Getter-to-setter roundtrips for various chunk types.
+  add_executable(pnggetset ${pnggetset_sources})
+  target_link_libraries(pnggetset
+                        PRIVATE png_shared)
+
+  png_add_test(NAME pnggetset
+               COMMAND pnggetset)
+
   # pngvalid tests:
   # Internal validation of standard and progressive reading,
   # transforms, and gamma handling.
diff --git a/Makefile.am b/Makefile.am
index 0126e20..5cd0381 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@
 
 # test programs - run on make check, make distcheck
 if ENABLE_TESTS
-check_PROGRAMS= pngtest pngunknown pngstest pngvalid pngimage pngcp
+check_PROGRAMS= pngtest pnggetset pngunknown pngstest pngvalid pngimage pngcp
 if HAVE_CLOCK_GETTIME
 check_PROGRAMS += timepng
 endif
@@ -42,6 +42,9 @@
 pngtest_SOURCES = pngtest.c
 pngtest_LDADD = libpng@PNGLIB_MAJOR@.la
 
+pnggetset_SOURCES = contrib/libtests/pnggetset.c
+pnggetset_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
+
 pngvalid_SOURCES = contrib/libtests/pngvalid.c
 pngvalid_LDADD = libpng@PNGLIB_MAJOR@.la
 
@@ -73,6 +76,7 @@
 if ENABLE_TESTS
 TESTS =\
    tests/pngtest-all\
+   tests/pnggetset\
    tests/pngvalid-gamma-16-to-8\
    tests/pngvalid-gamma-alpha-mode\
    tests/pngvalid-gamma-background\
@@ -254,9 +258,10 @@
 pngtest.o: pnglibconf.h
 
 contrib/libtests/makepng.o: pnglibconf.h
+contrib/libtests/pnggetset.o: pnglibconf.h
+contrib/libtests/pngimage.o: pnglibconf.h
 contrib/libtests/pngstest.o: pnglibconf.h
 contrib/libtests/pngunknown.o: pnglibconf.h
-contrib/libtests/pngimage.o: pnglibconf.h
 contrib/libtests/pngvalid.o: pnglibconf.h
 contrib/libtests/readpng.o: pnglibconf.h
 contrib/libtests/tarith.o: pnglibconf.h
diff --git a/arm/arm_init.c b/arm/arm_init.c
index 4a25f41..664d05d 100644
--- a/arm/arm_init.c
+++ b/arm/arm_init.c
@@ -186,7 +186,7 @@
          /* Finally update row_info to reflect the expanded output: */
          row_info->bit_depth = 8;
          row_info->pixel_depth = 32;
-         row_info->rowbytes = row_width * 4;
+         row_info->rowbytes = (size_t)row_width * 4;
          row_info->color_type = 6;
          row_info->channels = 4;
          return 1;
@@ -194,7 +194,7 @@
       else
       {
          /* No tRNS chunk (num_trans == 0), expand to RGB not RGBA. */
-         png_byte *dp = row + (3/*RGB*/*row_width - 1);
+         png_byte *dp = row + (3/*RGB*/ * (size_t)row_width - 1);
 
          png_uint_32 i = png_target_do_expand_palette_rgb8_neon(palette,
                row_info->width, &sp, &dp);
@@ -213,7 +213,7 @@
 
          row_info->bit_depth = 8;
          row_info->pixel_depth = 24;
-         row_info->rowbytes = row_width * 3;
+         row_info->rowbytes = (size_t)row_width * 3;
          row_info->color_type = 2;
          row_info->channels = 3;
          return 1;
diff --git a/contrib/libtests/pnggetset.c b/contrib/libtests/pnggetset.c
new file mode 100644
index 0000000..6ae43dc
--- /dev/null
+++ b/contrib/libtests/pnggetset.c
@@ -0,0 +1,648 @@
+/* pnggetset.c
+ *
+ * Copyright (c) 2026 Cosmin Truta
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ *
+ * Test the get-then-set roundtrip for chunk types whose getters return
+ * a pointer to internal storage.
+ *
+ * Passing such a pointer back into the corresponding setter must not
+ * cause a use-after-free.  A previous version freed the internal buffer
+ * before copying from the caller-supplied pointer.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
+#  include <config.h>
+#endif
+
+#ifdef PNG_FREESTANDING_TESTS
+#  include <png.h>
+#else
+#  include "../../png.h"
+#endif
+
+/* Test: get the PLTE, pass it straight back to set, verify roundtrip. */
+static int
+test_plte_roundtrip(void)
+{
+   png_structp png_ptr;
+   png_infop info_ptr;
+   png_color palette[4];
+   png_colorp got_palette = NULL;
+   int num_palette = 0;
+   int i;
+
+   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+       NULL, NULL, NULL);
+   if (png_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
+      return 1;
+   }
+
+   info_ptr = png_create_info_struct(png_ptr);
+   if (info_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
+      png_destroy_write_struct(&png_ptr, NULL);
+      return 1;
+   }
+
+   if (setjmp(png_jmpbuf(png_ptr)))
+   {
+      fprintf(stderr, "pnggetset: libpng error in test_plte_roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* Set up a palette-color image header. */
+   png_set_IHDR(png_ptr, info_ptr, 1, 1, 8, PNG_COLOR_TYPE_PALETTE,
+       PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+   /* Populate with recognizable values. */
+   for (i = 0; i < 4; i++)
+   {
+      palette[i].red   = (png_byte)(i * 10);
+      palette[i].green = (png_byte)(i * 20);
+      palette[i].blue  = (png_byte)(i * 30);
+   }
+   png_set_PLTE(png_ptr, info_ptr, palette, 4);
+
+   /* Get the internal pointer and feed it straight back. */
+   png_get_PLTE(png_ptr, info_ptr, &got_palette, &num_palette);
+   if (got_palette == NULL || num_palette != 4)
+   {
+      fprintf(stderr, "pnggetset: png_get_PLTE returned unexpected values\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* This is the critical call: the pointer aliases info_ptr->palette. */
+   png_set_PLTE(png_ptr, info_ptr, got_palette, num_palette);
+
+   /* Verify the data survived the roundtrip. */
+   got_palette = NULL;
+   num_palette = 0;
+   png_get_PLTE(png_ptr, info_ptr, &got_palette, &num_palette);
+   if (got_palette == NULL || num_palette != 4)
+   {
+      fprintf(stderr, "pnggetset: PLTE lost after roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+   for (i = 0; i < 4; i++)
+   {
+      if (got_palette[i].red   != (png_byte)(i * 10) ||
+          got_palette[i].green != (png_byte)(i * 20) ||
+          got_palette[i].blue  != (png_byte)(i * 30))
+      {
+         fprintf(stderr,
+             "pnggetset: PLTE entry %d corrupted after roundtrip\n", i);
+         png_destroy_write_struct(&png_ptr, &info_ptr);
+         return 1;
+      }
+   }
+
+   png_destroy_write_struct(&png_ptr, &info_ptr);
+   return 0;
+}
+
+#ifdef PNG_hIST_SUPPORTED
+/* Test: get the hIST, pass it straight back to set, verify roundtrip. */
+static int
+test_hist_roundtrip(void)
+{
+   png_structp png_ptr;
+   png_infop info_ptr;
+   png_color palette[4];
+   png_uint_16 hist[4];
+   png_uint_16p got_hist = NULL;
+   int i;
+
+   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+       NULL, NULL, NULL);
+   if (png_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
+      return 1;
+   }
+
+   info_ptr = png_create_info_struct(png_ptr);
+   if (info_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
+      png_destroy_write_struct(&png_ptr, NULL);
+      return 1;
+   }
+
+   if (setjmp(png_jmpbuf(png_ptr)))
+   {
+      fprintf(stderr, "pnggetset: libpng error in test_hist_roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* Set up a palette-color image header. */
+   memset(palette, 0, sizeof palette);
+   png_set_IHDR(png_ptr, info_ptr, 1, 1, 8, PNG_COLOR_TYPE_PALETTE,
+       PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+   png_set_PLTE(png_ptr, info_ptr, palette, 4);
+
+   /* Populate with recognizable values. */
+   for (i = 0; i < 4; i++)
+      hist[i] = (png_uint_16)(i * 100 + 42);
+
+   png_set_hIST(png_ptr, info_ptr, hist);
+
+   /* Get the internal pointer and feed it straight back. */
+   if (png_get_hIST(png_ptr, info_ptr, &got_hist) == 0 || got_hist == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_get_hIST returned unexpected values\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* This is the critical call: the pointer aliases info_ptr->hist. */
+   png_set_hIST(png_ptr, info_ptr, got_hist);
+
+   /* Verify the data survived the roundtrip. */
+   got_hist = NULL;
+   if (png_get_hIST(png_ptr, info_ptr, &got_hist) == 0 || got_hist == NULL)
+   {
+      fprintf(stderr, "pnggetset: hIST lost after roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+   for (i = 0; i < 4; i++)
+   {
+      if (got_hist[i] != (png_uint_16)(i * 100 + 42))
+      {
+         fprintf(stderr,
+             "pnggetset: hIST entry %d corrupted after roundtrip\n", i);
+         png_destroy_write_struct(&png_ptr, &info_ptr);
+         return 1;
+      }
+   }
+
+   png_destroy_write_struct(&png_ptr, &info_ptr);
+   return 0;
+}
+#endif /* PNG_hIST_SUPPORTED */
+
+#ifdef PNG_tRNS_SUPPORTED
+/* Test: get the tRNS, pass it straight back to set, verify roundtrip. */
+static int
+test_trns_roundtrip(void)
+{
+   png_structp png_ptr;
+   png_infop info_ptr;
+   png_color palette[4];
+   png_byte trans_alpha[4];
+   png_color_16 trans_color;
+   png_bytep got_alpha = NULL;
+   png_color_16p got_color = NULL;
+   int num_trans = 0;
+   int i;
+
+   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+       NULL, NULL, NULL);
+   if (png_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
+      return 1;
+   }
+
+   info_ptr = png_create_info_struct(png_ptr);
+   if (info_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
+      png_destroy_write_struct(&png_ptr, NULL);
+      return 1;
+   }
+
+   if (setjmp(png_jmpbuf(png_ptr)))
+   {
+      fprintf(stderr, "pnggetset: libpng error in test_trns_roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* Set up a palette-color image. */
+   memset(palette, 0, sizeof palette);
+   png_set_IHDR(png_ptr, info_ptr, 1, 1, 8, PNG_COLOR_TYPE_PALETTE,
+       PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+   png_set_PLTE(png_ptr, info_ptr, palette, 4);
+
+   /* Populate tRNS with recognizable values. */
+   for (i = 0; i < 4; i++)
+      trans_alpha[i] = (png_byte)(0xff - i * 0x11);
+   memset(&trans_color, 0, sizeof trans_color);
+
+   png_set_tRNS(png_ptr, info_ptr, trans_alpha, 4, &trans_color);
+
+   /* Get the internal pointer and feed it straight back. */
+   png_get_tRNS(png_ptr, info_ptr, &got_alpha, &num_trans, &got_color);
+   if (got_alpha == NULL || num_trans != 4)
+   {
+      fprintf(stderr, "pnggetset: png_get_tRNS returned unexpected values\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* This is the critical call: the pointer aliases info_ptr->trans_alpha. */
+   png_set_tRNS(png_ptr, info_ptr, got_alpha, num_trans, got_color);
+
+   /* Verify the data survived the roundtrip. */
+   got_alpha = NULL;
+   num_trans = 0;
+   png_get_tRNS(png_ptr, info_ptr, &got_alpha, &num_trans, &got_color);
+   if (got_alpha == NULL || num_trans != 4)
+   {
+      fprintf(stderr, "pnggetset: tRNS lost after roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+   for (i = 0; i < 4; i++)
+   {
+      if (got_alpha[i] != (png_byte)(0xff - i * 0x11))
+      {
+         fprintf(stderr,
+             "pnggetset: tRNS entry %d corrupted after roundtrip\n", i);
+         png_destroy_write_struct(&png_ptr, &info_ptr);
+         return 1;
+      }
+   }
+
+   png_destroy_write_struct(&png_ptr, &info_ptr);
+   return 0;
+}
+#endif /* PNG_tRNS_SUPPORTED */
+
+#ifdef PNG_TEXT_SUPPORTED
+/* Test: get the text array, pass it straight back to set, verify data. */
+#define TEXT_COUNT 6 /* enough to trigger reallocation on the second set */
+static int
+test_text_roundtrip(void)
+{
+   png_structp png_ptr;
+   png_infop info_ptr;
+   png_text text_entries[TEXT_COUNT];
+   png_textp got_text = NULL;
+   int got_num_text = 0;
+   int i;
+
+   /* Recognizable keys and values. */
+   static const char *keys[TEXT_COUNT] = {
+      "Title", "Author", "Desc", "Copyright", "Source", "Comment"
+   };
+   static const char *vals[TEXT_COUNT] = {
+      "t0", "t1", "t2", "t3", "t4", "t5"
+   };
+
+   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+       NULL, NULL, NULL);
+   if (png_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
+      return 1;
+   }
+
+   info_ptr = png_create_info_struct(png_ptr);
+   if (info_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
+      png_destroy_write_struct(&png_ptr, NULL);
+      return 1;
+   }
+
+   if (setjmp(png_jmpbuf(png_ptr)))
+   {
+      fprintf(stderr, "pnggetset: libpng error in test_text_roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* Populate the text entries. */
+   memset(text_entries, 0, sizeof text_entries);
+   for (i = 0; i < TEXT_COUNT; i++)
+   {
+      text_entries[i].compression = PNG_TEXT_COMPRESSION_NONE;
+      text_entries[i].key = (png_charp)keys[i];
+      text_entries[i].text = (png_charp)vals[i];
+   }
+   png_set_text(png_ptr, info_ptr, text_entries, TEXT_COUNT);
+
+   /* Get the internal pointer and feed it straight back (append). */
+   png_get_text(png_ptr, info_ptr, &got_text, &got_num_text);
+   if (got_text == NULL || got_num_text != TEXT_COUNT)
+   {
+      fprintf(stderr, "pnggetset: png_get_text returned unexpected values\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* This is the critical call: got_text aliases info_ptr->text. */
+   png_set_text(png_ptr, info_ptr, got_text, got_num_text);
+
+   /* Verify the original entries survived. */
+   got_text = NULL;
+   got_num_text = 0;
+   png_get_text(png_ptr, info_ptr, &got_text, &got_num_text);
+   if (got_text == NULL || got_num_text != TEXT_COUNT * 2)
+   {
+      fprintf(stderr, "pnggetset: text count %d, expected %d after roundtrip\n",
+          got_num_text, TEXT_COUNT * 2);
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+   for (i = 0; i < TEXT_COUNT; i++)
+   {
+      if (got_text[i].key == NULL ||
+          strcmp(got_text[i].key, keys[i]) != 0 ||
+          got_text[i].text == NULL ||
+          strcmp(got_text[i].text, vals[i]) != 0)
+      {
+         fprintf(stderr,
+             "pnggetset: text entry %d corrupted after roundtrip\n", i);
+         png_destroy_write_struct(&png_ptr, &info_ptr);
+         return 1;
+      }
+   }
+
+   png_destroy_write_struct(&png_ptr, &info_ptr);
+   return 0;
+}
+#undef TEXT_COUNT
+#endif /* PNG_TEXT_SUPPORTED */
+
+#ifdef PNG_sPLT_SUPPORTED
+/* Test: get the sPLT array, pass it straight back to set, verify data. */
+static int
+test_splt_roundtrip(void)
+{
+   png_structp png_ptr;
+   png_infop info_ptr;
+   png_sPLT_t splt;
+   png_sPLT_entry splt_entries[4];
+   png_sPLT_tp got_spalettes = NULL;
+   int got_num, i;
+
+   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+       NULL, NULL, NULL);
+   if (png_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
+      return 1;
+   }
+
+   info_ptr = png_create_info_struct(png_ptr);
+   if (info_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
+      png_destroy_write_struct(&png_ptr, NULL);
+      return 1;
+   }
+
+   if (setjmp(png_jmpbuf(png_ptr)))
+   {
+      fprintf(stderr, "pnggetset: libpng error in test_splt_roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* Populate with recognizable values. */
+   memset(splt_entries, 0, sizeof splt_entries);
+   for (i = 0; i < 4; i++)
+   {
+      splt_entries[i].red = (png_uint_16)(i * 1000);
+      splt_entries[i].green = (png_uint_16)(i * 2000);
+      splt_entries[i].blue = (png_uint_16)(i * 3000);
+      splt_entries[i].alpha = 0xffffU;
+      splt_entries[i].frequency = (png_uint_16)(i + 1);
+   }
+   memset(&splt, 0, sizeof splt);
+   splt.name = (png_charp)"test_sPLT";
+   splt.depth = 16;
+   splt.entries = splt_entries;
+   splt.nentries = 4;
+
+   png_set_sPLT(png_ptr, info_ptr, &splt, 1);
+
+   /* Get the internal pointer and feed it straight back (append). */
+   got_num = png_get_sPLT(png_ptr, info_ptr, &got_spalettes);
+   if (got_spalettes == NULL || got_num != 1)
+   {
+      fprintf(stderr, "pnggetset: png_get_sPLT returned unexpected values\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* This is the critical call: got_spalettes aliases internal storage. */
+   png_set_sPLT(png_ptr, info_ptr, got_spalettes, got_num);
+
+   /* Verify the original entry survived. */
+   got_spalettes = NULL;
+   got_num = png_get_sPLT(png_ptr, info_ptr, &got_spalettes);
+   if (got_spalettes == NULL || got_num != 2)
+   {
+      fprintf(stderr, "pnggetset: sPLT count %d, expected 2 after roundtrip\n",
+          got_num);
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+   if (strcmp(got_spalettes[0].name, "test_sPLT") != 0 ||
+       got_spalettes[0].nentries != 4 ||
+       got_spalettes[0].depth != 16)
+   {
+      fprintf(stderr,
+          "pnggetset: sPLT entry 0 corrupted after roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+   for (i = 0; i < 4; i++)
+   {
+      if (got_spalettes[0].entries[i].red != (png_uint_16)(i * 1000) ||
+          got_spalettes[0].entries[i].green != (png_uint_16)(i * 2000) ||
+          got_spalettes[0].entries[i].blue != (png_uint_16)(i * 3000))
+      {
+         fprintf(stderr,
+             "pnggetset: sPLT[0] entry %d corrupted after roundtrip\n", i);
+         png_destroy_write_struct(&png_ptr, &info_ptr);
+         return 1;
+      }
+   }
+
+   png_destroy_write_struct(&png_ptr, &info_ptr);
+   return 0;
+}
+#endif /* PNG_sPLT_SUPPORTED */
+
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+/* Test: get unknown chunks, pass them straight back to set, verify data. */
+static int
+test_unknown_roundtrip(void)
+{
+   png_structp png_ptr;
+   png_infop info_ptr;
+   png_unknown_chunk unk;
+   png_unknown_chunkp got_unknowns = NULL;
+   int got_num;
+   static const png_byte test_data[] = {0xde, 0xad, 0xbe, 0xef};
+
+   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+       NULL, NULL, NULL);
+   if (png_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_write_struct failed\n");
+      return 1;
+   }
+
+   info_ptr = png_create_info_struct(png_ptr);
+   if (info_ptr == NULL)
+   {
+      fprintf(stderr, "pnggetset: png_create_info_struct failed\n");
+      png_destroy_write_struct(&png_ptr, NULL);
+      return 1;
+   }
+
+   if (setjmp(png_jmpbuf(png_ptr)))
+   {
+      fprintf(stderr,
+          "pnggetset: libpng error in test_unknown_roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* Set up an unknown chunk with recognizable data. */
+   memset(&unk, 0, sizeof unk);
+   memcpy(unk.name, "teSt", 5);
+   unk.data = (png_bytep)test_data;
+   unk.size = sizeof test_data;
+   unk.location = PNG_HAVE_IHDR;
+
+   png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0);
+   png_set_unknown_chunks(png_ptr, info_ptr, &unk, 1);
+
+   /* Get the internal pointer and feed it straight back (append). */
+   got_num = png_get_unknown_chunks(png_ptr, info_ptr, &got_unknowns);
+   if (got_unknowns == NULL || got_num != 1)
+   {
+      fprintf(stderr,
+          "pnggetset: png_get_unknown_chunks returned unexpected values\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   /* This is the critical call: got_unknowns aliases internal storage. */
+   png_set_unknown_chunks(png_ptr, info_ptr, got_unknowns, got_num);
+
+   /* Verify the original entry survived. */
+   got_unknowns = NULL;
+   got_num = png_get_unknown_chunks(png_ptr, info_ptr, &got_unknowns);
+   if (got_unknowns == NULL || got_num != 2)
+   {
+      fprintf(stderr,
+          "pnggetset: unknown_chunks count %d, expected 2 after roundtrip\n",
+          got_num);
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+   if (memcmp(got_unknowns[0].name, "teSt", 4) != 0 ||
+       got_unknowns[0].size != sizeof test_data ||
+       memcmp(got_unknowns[0].data, test_data, sizeof test_data) != 0)
+   {
+      fprintf(stderr,
+          "pnggetset: unknown chunk 0 corrupted after roundtrip\n");
+      png_destroy_write_struct(&png_ptr, &info_ptr);
+      return 1;
+   }
+
+   png_destroy_write_struct(&png_ptr, &info_ptr);
+   return 0;
+}
+#endif /* PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED */
+
+int
+main(void)
+{
+   int result = 0;
+
+   printf("Testing PLTE get-then-set roundtrip... ");
+   fflush(stdout);
+   if (test_plte_roundtrip() != 0)
+   {
+      printf("FAIL\n");
+      result = 1;
+   }
+   else
+      printf("PASS\n");
+
+#ifdef PNG_hIST_SUPPORTED
+   printf("Testing hIST get-then-set roundtrip... ");
+   fflush(stdout);
+   if (test_hist_roundtrip() != 0)
+   {
+      printf("FAIL\n");
+      result = 1;
+   }
+   else
+      printf("PASS\n");
+#endif
+
+#ifdef PNG_tRNS_SUPPORTED
+   printf("Testing tRNS get-then-set roundtrip... ");
+   fflush(stdout);
+   if (test_trns_roundtrip() != 0)
+   {
+      printf("FAIL\n");
+      result = 1;
+   }
+   else
+      printf("PASS\n");
+#endif
+
+#ifdef PNG_TEXT_SUPPORTED
+   printf("Testing tEXt get-then-set roundtrip... ");
+   fflush(stdout);
+   if (test_text_roundtrip() != 0)
+   {
+      printf("FAIL\n");
+      result = 1;
+   }
+   else
+      printf("PASS\n");
+#endif
+
+#ifdef PNG_sPLT_SUPPORTED
+   printf("Testing sPLT get-then-set roundtrip... ");
+   fflush(stdout);
+   if (test_splt_roundtrip() != 0)
+   {
+      printf("FAIL\n");
+      result = 1;
+   }
+   else
+      printf("PASS\n");
+#endif
+
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+   printf("Testing unknown chunks get-then-set roundtrip... ");
+   fflush(stdout);
+   if (test_unknown_roundtrip() != 0)
+   {
+      printf("FAIL\n");
+      result = 1;
+   }
+   else
+      printf("PASS\n");
+#endif
+
+   return result;
+}
diff --git a/manuals/libpng-manual.txt b/manuals/libpng-manual.txt
index 53af621..da40b1e 100644
--- a/manuals/libpng-manual.txt
+++ b/manuals/libpng-manual.txt
@@ -9,7 +9,7 @@
 
  Based on:
 
- libpng version 1.6.36, December 2018, through 1.6.56 - March 2026
+ libpng version 1.6.36, December 2018, through 1.6.57 - April 2026
  Updated and distributed by Cosmin Truta
  Copyright (c) 2018-2026 Cosmin Truta
 
diff --git a/manuals/libpng.3 b/manuals/libpng.3
index 730e99d..512a6d1 100644
--- a/manuals/libpng.3
+++ b/manuals/libpng.3
@@ -1,4 +1,4 @@
-.TH LIBPNG 3 "March 25, 2026"
+.TH LIBPNG 3 "April 8, 2026"
 .SH NAME
 libpng \- Portable Network Graphics (PNG) Reference Library 1.8.0.git
 
@@ -516,7 +516,7 @@
 
  Based on:
 
- libpng version 1.6.36, December 2018, through 1.6.56 - March 2026
+ libpng version 1.6.36, December 2018, through 1.6.57 - April 2026
  Updated and distributed by Cosmin Truta
  Copyright (c) 2018-2026 Cosmin Truta
 
diff --git a/manuals/png.5 b/manuals/png.5
index 7859b7e..df25110 100644
--- a/manuals/png.5
+++ b/manuals/png.5
@@ -1,4 +1,4 @@
-.TH PNG 5 "March 25, 2026"
+.TH PNG 5 "April 8, 2026"
 .SH NAME
 png \- Portable Network Graphics (PNG) format
 
diff --git a/png.h b/png.h
index a7e6582..6dc5c4c 100644
--- a/png.h
+++ b/png.h
@@ -14,7 +14,7 @@
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
  *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
  *     Glenn Randers-Pehrson
- *   libpng versions 1.6.36, December 2018, through 1.6.56, March 2026:
+ *   libpng versions 1.6.36, December 2018, through 1.6.57, April 2026:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
diff --git a/pngrtran.c b/pngrtran.c
index 911dc16..85af06b 100644
--- a/pngrtran.c
+++ b/pngrtran.c
@@ -2361,7 +2361,7 @@
       }
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_width * row_info->channels;
+      row_info->rowbytes = (size_t)row_width * row_info->channels;
    }
 }
 #endif
@@ -2563,7 +2563,7 @@
 
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_info->width * row_info->channels;
+      row_info->rowbytes = (size_t)row_info->width * row_info->channels;
    }
 }
 #endif
@@ -2591,7 +2591,7 @@
 
       row_info->bit_depth = 8;
       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
-      row_info->rowbytes = row_info->width * row_info->channels;
+      row_info->rowbytes = (size_t)row_info->width * row_info->channels;
    }
 }
 #endif
@@ -2827,7 +2827,7 @@
             *(--dp) = lo_filler;
             row_info->channels = 2;
             row_info->pixel_depth = 16;
-            row_info->rowbytes = row_width * 2;
+            row_info->rowbytes = (size_t)row_width * 2;
          }
 
          else
@@ -2842,7 +2842,7 @@
             }
             row_info->channels = 2;
             row_info->pixel_depth = 16;
-            row_info->rowbytes = row_width * 2;
+            row_info->rowbytes = (size_t)row_width * 2;
          }
       }
 
@@ -2865,7 +2865,7 @@
             *(--dp) = hi_filler;
             row_info->channels = 2;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
 
          else
@@ -2882,7 +2882,7 @@
             }
             row_info->channels = 2;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
       }
 #endif
@@ -2906,7 +2906,7 @@
             *(--dp) = lo_filler;
             row_info->channels = 4;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
 
          else
@@ -2923,7 +2923,7 @@
             }
             row_info->channels = 4;
             row_info->pixel_depth = 32;
-            row_info->rowbytes = row_width * 4;
+            row_info->rowbytes = (size_t)row_width * 4;
          }
       }
 
@@ -2950,7 +2950,7 @@
             *(--dp) = hi_filler;
             row_info->channels = 4;
             row_info->pixel_depth = 64;
-            row_info->rowbytes = row_width * 8;
+            row_info->rowbytes = (size_t)row_width * 8;
          }
 
          else
@@ -2972,7 +2972,7 @@
 
             row_info->channels = 4;
             row_info->pixel_depth = 64;
-            row_info->rowbytes = row_width * 8;
+            row_info->rowbytes = (size_t)row_width * 8;
          }
       }
 #endif
@@ -4451,7 +4451,7 @@
                }
                row_info->bit_depth = 8;
                row_info->pixel_depth = 32;
-               row_info->rowbytes = row_width * 4;
+               row_info->rowbytes = (size_t)row_width * 4;
                row_info->color_type = 6;
                row_info->channels = 4;
             }
@@ -4459,7 +4459,7 @@
             else
             {
                sp = row + (size_t)row_width - 1;
-               dp = row + (size_t)(row_width * 3) - 1;
+               dp = row + (size_t)row_width * 3 - 1;
                for (i = 0; i < row_width; i++)
                {
                   *dp-- = palette[*sp].blue;
@@ -4470,7 +4470,7 @@
 
                row_info->bit_depth = 8;
                row_info->pixel_depth = 24;
-               row_info->rowbytes = row_width * 3;
+               row_info->rowbytes = (size_t)row_width * 3;
                row_info->color_type = 2;
                row_info->channels = 3;
             }
diff --git a/pngset.c b/pngset.c
index 23a18bb..773a2f8 100644
--- a/pngset.c
+++ b/pngset.c
@@ -376,6 +376,7 @@
 png_set_hIST(const png_struct *png_ptr, png_info *info_ptr,
     const png_uint_16 *hist)
 {
+   png_uint_16 safe_hist[PNG_MAX_PALETTE_LENGTH];
    int i;
 
    png_debug1(1, "in %s storage function", "hIST");
@@ -392,6 +393,13 @@
       return;
    }
 
+   /* Snapshot the caller's hist before freeing, in case it points to
+    * info_ptr->hist (getter-to-setter aliasing).
+    */
+   memcpy(safe_hist, hist, (unsigned int)info_ptr->num_palette *
+       (sizeof (png_uint_16)));
+   hist = safe_hist;
+
    png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
 
    /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
@@ -740,7 +748,7 @@
 png_set_PLTE(png_struct *png_ptr, png_info *info_ptr,
     const png_color *palette, int num_palette)
 {
-
+   png_color safe_palette[PNG_MAX_PALETTE_LENGTH];
    png_uint_32 max_palette_length;
 
    png_debug1(1, "in %s storage function", "PLTE");
@@ -774,6 +782,15 @@
       png_error(png_ptr, "Invalid palette");
    }
 
+   /* Snapshot the caller's palette before freeing, in case it points to
+    * info_ptr->palette (getter-to-setter aliasing).
+    */
+   if (num_palette > 0)
+      memcpy(safe_palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
+
+   palette = safe_palette;
+
    png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
 
    /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
@@ -935,6 +952,7 @@
     const png_text *text_ptr, int num_text)
 {
    int i;
+   png_textp old_text = NULL;
 
    png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
       png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
@@ -982,7 +1000,10 @@
          return 1;
       }
 
-      png_free(png_ptr, info_ptr->text);
+      /* Defer freeing the old array until after the copy loop below,
+       * in case text_ptr aliases info_ptr->text (getter-to-setter).
+       */
+      old_text = info_ptr->text;
 
       info_ptr->text = new_text;
       info_ptr->free_me |= PNG_FREE_TEXT;
@@ -1067,6 +1088,7 @@
       {
          png_chunk_report(png_ptr, "text chunk: out of memory",
              PNG_CHUNK_WRITE_ERROR);
+         png_free(png_ptr, old_text);
 
          return 1;
       }
@@ -1120,6 +1142,8 @@
       png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
    }
 
+   png_free(png_ptr, old_text);
+
    return 0;
 }
 #endif
@@ -1163,6 +1187,16 @@
 
    if (trans_alpha != NULL)
    {
+       /* Snapshot the caller's trans_alpha before freeing, in case it
+        * points to info_ptr->trans_alpha (getter-to-setter aliasing).
+        */
+       png_byte safe_trans[PNG_MAX_PALETTE_LENGTH];
+
+       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
+          memcpy(safe_trans, trans_alpha, (size_t)num_trans);
+
+       trans_alpha = safe_trans;
+
        png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
 
        if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
@@ -1247,6 +1281,7 @@
  */
 {
    png_sPLT_t *np;
+   png_sPLT_t *old_spalettes;
 
    png_debug1(1, "in %s storage function", "sPLT");
 
@@ -1267,7 +1302,10 @@
       return;
    }
 
-   png_free(png_ptr, info_ptr->splt_palettes);
+   /* Defer freeing the old array until after the copy loop below,
+    * in case entries aliases info_ptr->splt_palettes (getter-to-setter).
+    */
+   old_spalettes = info_ptr->splt_palettes;
 
    info_ptr->splt_palettes = np;
    info_ptr->free_me |= PNG_FREE_SPLT;
@@ -1331,6 +1369,8 @@
    }
    while (--nentries);
 
+   png_free(png_ptr, old_spalettes);
+
    if (nentries > 0)
       png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
 }
@@ -1517,6 +1557,7 @@
     png_info *info_ptr, const png_unknown_chunk *unknowns, int num_unknowns)
 {
    png_unknown_chunk *np;
+   png_unknown_chunk *old_unknowns;
 
    if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
        unknowns == NULL)
@@ -1563,7 +1604,10 @@
       return;
    }
 
-   png_free(png_ptr, info_ptr->unknown_chunks);
+   /* Defer freeing the old array until after the copy loop below,
+    * in case unknowns aliases info_ptr->unknown_chunks (getter-to-setter).
+    */
+   old_unknowns = info_ptr->unknown_chunks;
 
    info_ptr->unknown_chunks = np; /* safe because it is initialized */
    info_ptr->free_me |= PNG_FREE_UNKN;
@@ -1609,6 +1653,8 @@
       ++np;
       ++(info_ptr->unknown_chunks_num);
    }
+
+   png_free(png_ptr, old_unknowns);
 }
 
 void
diff --git a/tests/pnggetset b/tests/pnggetset
new file mode 100755
index 0000000..57ef731
--- /dev/null
+++ b/tests/pnggetset
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+# pnggetset test:
+# Getter-to-setter roundtrips for various chunk types.
+exec ./pnggetset