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};