Commit 29b9ae2d for libheif

commit 29b9ae2d6516d01c9c13d4aa798acce60f854753
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Fri May 15 00:54:15 2026 +0200

    protect HeifPixelImage padding to custom component size configurations

diff --git a/libheif/image/pixelimage.cc b/libheif/image/pixelimage.cc
index 4cc4288e..9d1c9331 100644
--- a/libheif/image/pixelimage.cc
+++ b/libheif/image/pixelimage.cc
@@ -488,6 +488,19 @@ Error HeifPixelImage::extend_padding_to_size(uint32_t width, uint32_t height, bo
                                              const heif_security_limits* limits)
 {
   for (auto& component : m_storage) {
+    // get_subsampled_size() only adjusts the size for Cb/Cr; for every other
+    // channel it assumes the component has the full logical image size. We
+    // cannot compute a correct padded size for a non-Cb/Cr component that does
+    // not follow that assumption (e.g. multi-component ISO 23001-17 images).
+    if ((component.m_width != m_width ||
+         component.m_height != m_height) &&
+        (component.m_channel != heif_channel_Cb &&
+         component.m_channel != heif_channel_Cr)) {
+      return Error{heif_error_Unsupported_feature,
+                   heif_suberror_Unspecified,
+                   "Cannot extend padding for an image with non-uniform component sizes."};
+    }
+
     uint32_t subsampled_width, subsampled_height;
     get_subsampled_size(width, height, component.m_channel, m_chroma,
                         &subsampled_width, &subsampled_height);
@@ -565,6 +578,18 @@ Error HeifPixelImage::extend_padding_to_size(uint32_t width, uint32_t height, bo
 Error HeifPixelImage::extend_to_size_with_zero(uint32_t width, uint32_t height, const heif_security_limits* limits)
 {
   for (auto& component : m_storage) {
+    // See extend_padding_to_size(): get_subsampled_size() assumes a non-Cb/Cr
+    // component has the full logical image size, so we cannot compute a correct
+    // target size for a component that does not follow that assumption.
+    if ((component.m_width != m_width ||
+         component.m_height != m_height) &&
+        (component.m_channel != heif_channel_Cb &&
+         component.m_channel != heif_channel_Cr)) {
+      return Error{heif_error_Unsupported_feature,
+                   heif_suberror_Unspecified,
+                   "Cannot extend an image with non-uniform component sizes."};
+    }
+
     uint32_t subsampled_width, subsampled_height;
     get_subsampled_size(width, height, component.m_channel, m_chroma,
                         &subsampled_width, &subsampled_height);
diff --git a/libheif/image/pixelimage.h b/libheif/image/pixelimage.h
index 49beb7ac..3b93ae65 100644
--- a/libheif/image/pixelimage.h
+++ b/libheif/image/pixelimage.h
@@ -371,7 +371,7 @@ private:
   // once allocation has succeeded so that no descriptions are registered for
   // a plane that failed to materialize.
   void register_component_descriptions(ComponentStorage& plane,
-                                   const std::vector<uint16_t>& component_types);
+                                       const std::vector<uint16_t>& component_types);

   // Overload that clones existing ComponentDescriptions (preserving
   // component_type, gimi_content_id, has_data_plane, and any other per-id
@@ -380,7 +380,7 @@ private:
   // when allocating a new plane that mirrors an existing one (e.g.
   // geometry-preserving transforms like rotation and crop).
   void register_component_descriptions(ComponentStorage& plane,
-                                   const std::vector<const ComponentDescription*>& source_descriptions);
+                                       const std::vector<const ComponentDescription*>& source_descriptions);

   uint32_t m_width = 0;
   uint32_t m_height = 0;
@@ -388,15 +388,8 @@ private:
   heif_chroma m_chroma = heif_chroma_undefined;

   std::vector<ComponentStorage> m_storage;
-  //std::vector<uint16_t> m_cmpd_component_types;  // indexed by cmpd index
   MemoryHandle m_memory_handle;

-  // (component_type now lives on each ComponentDescription in
-  //  ImageDescription::m_components, indexed by component_id.)
-
-  // m_next_component_id and m_sample_duration moved to ImageDescription
-  // (inherited).
-
   std::vector<Error> m_warnings;
 };