Commit 9d955409 for libheif

commit 9d955409c56d2f1c6d448fd8c95c1d5a25954366
Author: Zhaoqi Xu <lzy00419@outlook.com>
Date:   Tue Oct 20 21:54:28 2026 -0400

    libde265: pass the NAL size limit through and report push errors

    libde265 1.1.0 rejects NAL units larger than 16 MiB by default. libheif
    only forwarded max_image_size_pixels, so this limit could not be changed,
    not even with the security limits disabled, and large coded images
    (e.g. lossless encodes) that libheif writes could not be decoded again.

    Set max_NAL_size_bytes from max_memory_block_size, which already bounds
    the item data that is read into memory. Also return the error from
    de265_push_NAL() instead of ignoring it, so a rejected NAL is reported
    instead of the generic 'did not give a decompressed image' error.

    Fixes #1936

diff --git a/libheif/plugins/decoder_libde265.cc b/libheif/plugins/decoder_libde265.cc
index 8a74160f..2f86ebe5 100644
--- a/libheif/plugins/decoder_libde265.cc
+++ b/libheif/plugins/decoder_libde265.cc
@@ -195,6 +195,17 @@ heif_error libde265_new_decoder2(void** dec, const heif_decoder_plugin_options*
     else {
       de265_limits->max_image_size_pixels = static_cast<uint32_t>(limits->max_image_size_pixels);
     }
+
+    // libde265 rejects NAL units larger than 16 MiB by default. libheif has already
+    // read the whole item into memory under max_memory_block_size, so use that
+    // limit for the NAL size too. Otherwise, large images (e.g. lossless) that
+    // libheif can write could not be decoded, even with the limits disabled.
+    if (limits->max_memory_block_size > std::numeric_limits<uint32_t>::max()) {
+      de265_limits->max_NAL_size_bytes = 0;
+    }
+    else {
+      de265_limits->max_NAL_size_bytes = static_cast<uint32_t>(limits->max_memory_block_size);
+    }
   }
 #endif

@@ -358,11 +369,18 @@ static heif_error libde265_v1_push_data2(void* decoder_raw, const void* data, si
 #endif

     // The codec hands this opaque pointer back unchanged; it carries an integer, not an address.
-    de265_push_NAL(decoder->ctx, cdata + ptr, nal_size, 0, (void*)user_data); // NOLINT(performance-no-int-to-ptr)
+    de265_error push_err = de265_push_NAL(decoder->ctx, cdata + ptr, nal_size, 0, (void*)user_data); // NOLINT(performance-no-int-to-ptr)
+    if (!de265_isOK(push_err)) {
+      return {
+        heif_error_Decoder_plugin_error,
+        heif_suberror_Unspecified,
+        de265_get_error_text(push_err)
+      };
+    }
+
     ptr += nal_size;
   }

-  // TODO(farindk): Set "err" if data could not be pushed
   //de265_push_data(decoder->ctx, data, size, 0, nullptr);

   return {heif_error_Ok, heif_suberror_Unspecified, kSuccess};