Commit 4e9ba9ce for libheif
commit 4e9ba9ce26e8bab47404708fc508b0d814af6146
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Thu Dec 18 14:40:28 2025 +0100
[BSD3] fix potential endless loop when trying to decode incomplete input data (#1640)
diff --git a/libheif/codecs/decoder.cc b/libheif/codecs/decoder.cc
index 967db5c7..48105a9d 100644
--- a/libheif/codecs/decoder.cc
+++ b/libheif/codecs/decoder.cc
@@ -430,7 +430,12 @@ Decoder::decode_single_frame_from_compressed_data(const heif_decoding_options& o
flush_decoder();
- for (;;) {
+ // We might have to try several times to get an image out of the decoder.
+ // However, we stop after a maximum number of tries because the decoder might not
+ // give any image when the input data is incomplete.
+ const int max_decoding_tries = 50; // hardcoded value, should be large enough
+
+ for (int i = 0; i < max_decoding_tries; i++) {
Result<std::shared_ptr<HeifPixelImage>> imgResult;
imgResult = get_decoded_frame(options, nullptr, limits);
if (imgResult.error()) {
@@ -441,4 +446,12 @@ Decoder::decode_single_frame_from_compressed_data(const heif_decoding_options& o
return imgResult;
}
}
+
+ // We did not receive and image from the decoder. We give up.
+
+ return Error{
+ heif_error_Decoder_plugin_error,
+ heif_suberror_Unspecified,
+ "Decoding the input data did not give a decompressed image."
+ };
}
diff --git a/libheif/image-items/image_item.cc b/libheif/image-items/image_item.cc
index ce21e092..797df4ec 100644
--- a/libheif/image-items/image_item.cc
+++ b/libheif/image-items/image_item.cc
@@ -937,6 +937,18 @@ Result<std::shared_ptr<HeifPixelImage>> ImageItem::decode_compressed_image(const
decoder->set_data_extent(std::move(extent));
+ // Check that we are pushing at least some data into the decoder.
+ // Some decoders (e.g. aom) do not complain when the input data is empty and we might
+ // get stuck in an endless decoding loop, waiting for the decompressed image.
+
+ if (extent.m_size == 0) {
+ return Error{
+ heif_error_Invalid_input,
+ heif_suberror_Unspecified,
+ "Input with empty data extent."
+ };
+ }
+
return decoder->decode_single_frame_from_compressed_data(options,
get_context()->get_security_limits());
}