Commit b75e61bf for libheif
commit b75e61bfb4863bd78839e33268b10d4a1e85faf0
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Fri May 15 12:33:37 2026 +0200
resolve endless recursion in get_id_of_non_virtual_child_image()
diff --git a/libheif/context.cc b/libheif/context.cc
index 9b24343d..2cadeed8 100644
--- a/libheif/context.cc
+++ b/libheif/context.cc
@@ -31,6 +31,7 @@
#include <limits>
#include <cmath>
#include <deque>
+#include <set>
#include "image-items/image_item.h"
#include <codecs/hevc_boxes.h>
#include "sequences/track.h"
@@ -1347,47 +1348,54 @@ bool HeifContext::has_alpha(heif_item_id ID) const
}
-Error HeifContext::get_id_of_non_virtual_child_image(heif_item_id id, heif_item_id& out) const
+Result<heif_item_id> HeifContext::find_first_coded_image_id(heif_item_id id) const
{
- uint32_t image_type = m_heif_file->get_item_type_4cc(id);
- if (image_type == fourcc("grid") ||
- image_type == fourcc("iden") ||
- image_type == fourcc("iovl")) {
- auto iref_box = m_heif_file->get_iref_box();
- if (!iref_box) {
+ std::set<heif_item_id> visited;
+
+ for (;;) {
+ if (!visited.insert(id).second) {
return Error(heif_error_Invalid_input,
heif_suberror_No_item_data,
- "Derived image does not reference any other image items");
+ "Derived image references form a cycle");
}
- std::vector<heif_item_id> image_references = iref_box->get_references(id, fourcc("dimg"));
+ uint32_t image_type = m_heif_file->get_item_type_4cc(id);
+ if (image_type == fourcc("grid") ||
+ image_type == fourcc("iden") ||
+ image_type == fourcc("iovl")) {
+ auto iref_box = m_heif_file->get_iref_box();
+ if (!iref_box) {
+ return Error(heif_error_Invalid_input,
+ heif_suberror_No_item_data,
+ "Derived image does not reference any other image items");
+ }
+
+ std::vector<heif_item_id> image_references = iref_box->get_references(id, fourcc("dimg"));
- // TODO: check whether this really can be recursive (e.g. overlay of grid images)
+ if (image_references.empty()) {
+ return Error(heif_error_Invalid_input,
+ heif_suberror_No_item_data,
+ "Derived image does not reference any other image items");
+ }
- if (image_references.empty() || image_references[0] == id) {
- return Error(heif_error_Invalid_input,
- heif_suberror_No_item_data,
- "Derived image does not reference any other image items");
+ // follow the first reference
+ id = image_references[0];
}
else {
- return get_id_of_non_virtual_child_image(image_references[0], out);
- }
- }
- else {
- if (!m_all_images.contains(id)) {
- std::stringstream sstr;
- sstr << "Image item " << id << " referenced, but it does not exist\n";
+ if (!m_all_images.contains(id)) {
+ std::stringstream sstr;
+ sstr << "Image item " << id << " referenced, but it does not exist\n";
- return Error(heif_error_Invalid_input,
- heif_suberror_Nonexisting_item_referenced,
- sstr.str());
- }
- else if (dynamic_cast<ImageItem_Error*>(m_all_images.find(id)->second.get())) {
- // Should er return an error here or leave it to the follow-up code to detect that?
- }
+ return Error(heif_error_Invalid_input,
+ heif_suberror_Nonexisting_item_referenced,
+ sstr.str());
+ }
+ else if (dynamic_cast<ImageItem_Error*>(m_all_images.find(id)->second.get())) {
+ // Should we return an error here or leave it to the follow-up code to detect that?
+ }
- out = id;
- return Error::Ok;
+ return id;
+ }
}
}
diff --git a/libheif/context.h b/libheif/context.h
index e773ce0b..898111fd 100644
--- a/libheif/context.h
+++ b/libheif/context.h
@@ -131,7 +131,7 @@ public:
heif_chroma out_chroma,
const heif_decoding_options& options) const;
- Error get_id_of_non_virtual_child_image(heif_item_id in, heif_item_id& out) const;
+ Result<heif_item_id> find_first_coded_image_id(heif_item_id in) const;
std::string debug_dump_boxes() const;
diff --git a/libheif/image-items/grid.cc b/libheif/image-items/grid.cc
index 55658808..08f07c4c 100644
--- a/libheif/image-items/grid.cc
+++ b/libheif/image-items/grid.cc
@@ -656,13 +656,12 @@ void ImageItem_Grid::get_tile_size(uint32_t& w, uint32_t& h) const
int ImageItem_Grid::get_luma_bits_per_pixel() const
{
- heif_item_id child;
- Error err = get_context()->get_id_of_non_virtual_child_image(get_id(), child);
- if (err) {
+ auto child_result = get_context()->find_first_coded_image_id(get_id());
+ if (child_result.is_error()) {
return -1;
}
- auto image = get_context()->get_image(child, true);
+ auto image = get_context()->get_image(*child_result, true);
if (!image) {
return -1;
}
@@ -673,25 +672,23 @@ int ImageItem_Grid::get_luma_bits_per_pixel() const
int ImageItem_Grid::get_chroma_bits_per_pixel() const
{
- heif_item_id child;
- Error err = get_context()->get_id_of_non_virtual_child_image(get_id(), child);
- if (err) {
+ auto child_result = get_context()->find_first_coded_image_id(get_id());
+ if (child_result.is_error()) {
return -1;
}
- auto image = get_context()->get_image(child, true);
+ auto image = get_context()->get_image(*child_result, true);
return image->get_chroma_bits_per_pixel();
}
Result<std::shared_ptr<Decoder>> ImageItem_Grid::get_decoder() const
{
- heif_item_id child;
- Error err = get_context()->get_id_of_non_virtual_child_image(get_id(), child);
- if (err) {
- return {err};
+ auto child_result = get_context()->find_first_coded_image_id(get_id());
+ if (child_result.is_error()) {
+ return child_result.error();
}
- auto image = get_context()->get_image(child, true);
+ auto image = get_context()->get_image(*child_result, true);
if (!image) {
return Error{heif_error_Invalid_input,
heif_suberror_Nonexisting_item_referenced};
diff --git a/libheif/image-items/iden.cc b/libheif/image-items/iden.cc
index b62a3b1b..8050af27 100644
--- a/libheif/image-items/iden.cc
+++ b/libheif/image-items/iden.cc
@@ -99,13 +99,12 @@ Result<std::shared_ptr<HeifPixelImage>> ImageItem_iden::decode_compressed_image(
Error ImageItem_iden::get_coded_image_colorspace(heif_colorspace* out_colorspace, heif_chroma* out_chroma) const
{
- heif_item_id child;
- Error err = get_context()->get_id_of_non_virtual_child_image(get_id(), child);
- if (err) {
- return err;
+ auto child_result = get_context()->find_first_coded_image_id(get_id());
+ if (child_result.is_error()) {
+ return child_result.error();
}
- auto image = get_context()->get_image(child, true);
+ auto image = get_context()->get_image(*child_result, true);
if (!image) {
return Error{heif_error_Invalid_input,
heif_suberror_Nonexisting_item_referenced};
@@ -117,13 +116,12 @@ Error ImageItem_iden::get_coded_image_colorspace(heif_colorspace* out_colorspace
int ImageItem_iden::get_luma_bits_per_pixel() const
{
- heif_item_id child;
- Error err = get_context()->get_id_of_non_virtual_child_image(get_id(), child);
- if (err) {
+ auto child_result = get_context()->find_first_coded_image_id(get_id());
+ if (child_result.is_error()) {
return -1;
}
- auto image = get_context()->get_image(child, true);
+ auto image = get_context()->get_image(*child_result, true);
if (!image) {
return -1;
}
@@ -134,13 +132,12 @@ int ImageItem_iden::get_luma_bits_per_pixel() const
int ImageItem_iden::get_chroma_bits_per_pixel() const
{
- heif_item_id child;
- Error err = get_context()->get_id_of_non_virtual_child_image(get_id(), child);
- if (err) {
+ auto child_result = get_context()->find_first_coded_image_id(get_id());
+ if (child_result.is_error()) {
return -1;
}
- auto image = get_context()->get_image(child, true);
+ auto image = get_context()->get_image(*child_result, true);
if (!image) {
return -1;
}
@@ -161,13 +158,12 @@ void ImageItem_iden::populate_component_descriptions()
return;
}
- heif_item_id child_id;
- Error err = get_context()->get_id_of_non_virtual_child_image(get_id(), child_id);
- if (err) {
+ auto child_result = get_context()->find_first_coded_image_id(get_id());
+ if (child_result.is_error()) {
return;
}
- auto child = get_context()->get_image(child_id, true);
+ auto child = get_context()->get_image(*child_result, true);
if (!child) {
return;
}
diff --git a/libheif/image-items/overlay.cc b/libheif/image-items/overlay.cc
index 705a9338..3e01075c 100644
--- a/libheif/image-items/overlay.cc
+++ b/libheif/image-items/overlay.cc
@@ -396,26 +396,24 @@ Result<std::shared_ptr<HeifPixelImage>> ImageItem_Overlay::decode_overlay_image(
int ImageItem_Overlay::get_luma_bits_per_pixel() const
{
- heif_item_id child;
- Error err = get_context()->get_id_of_non_virtual_child_image(get_id(), child);
- if (err) {
+ auto child_result = get_context()->find_first_coded_image_id(get_id());
+ if (child_result.is_error()) {
return -1;
}
- auto image = get_context()->get_image(child, true);
+ auto image = get_context()->get_image(*child_result, true);
return image->get_luma_bits_per_pixel();
}
int ImageItem_Overlay::get_chroma_bits_per_pixel() const
{
- heif_item_id child;
- Error err = get_context()->get_id_of_non_virtual_child_image(get_id(), child);
- if (err) {
+ auto child_result = get_context()->find_first_coded_image_id(get_id());
+ if (child_result.is_error()) {
return -1;
}
- auto image = get_context()->get_image(child, true);
+ auto image = get_context()->get_image(*child_result, true);
return image->get_chroma_bits_per_pixel();
}