Commit 23848438 for libheif

commit 238484384bbb2fe156cf644c6433eb7570e61717
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Sat May 16 01:36:36 2026 +0200

    check for valid heif_image_crop() parameters (#1788)

diff --git a/libheif/api/libheif/heif_image.cc b/libheif/api/libheif/heif_image.cc
index f766969b..bc54219f 100644
--- a/libheif/api/libheif/heif_image.cc
+++ b/libheif/api/libheif/heif_image.cc
@@ -84,16 +84,20 @@ heif_error heif_image_crop(heif_image* img,
   uint32_t w = img->image->get_width();
   uint32_t h = img->image->get_height();

-  if (w == 0 || w > 0x7FFFFFFF ||
-      h == 0 || h > 0x7FFFFFFF) {
+  // Margins must be non-negative and must not consume the entire image.
+  // Without this check, `left + right >= w` would underflow the unsigned
+  // `w - 1 - right` computation below and cause an OOB read (issue #1746).
+  if (left < 0 || right < 0 || top < 0 || bottom < 0 ||
+      static_cast<int64_t>(left) + right >= w ||
+      static_cast<int64_t>(top) + bottom >= h) {
     return heif_error{
       heif_error_Usage_error,
-      heif_suberror_Invalid_image_size,
-      "Image size exceeds maximum supported size"
+      heif_suberror_Invalid_parameter_value,
+      "Invalid crop margins"
     };
   }

-  auto cropResult = img->image->crop(left, static_cast<int>(w) - 1 - right, top, static_cast<int>(h) - 1 - bottom, nullptr);
+  auto cropResult = img->image->crop(left, w - 1 - right, top, h - 1 - bottom, nullptr);
   if (!cropResult) {
     return cropResult.error_struct(img->image.get());
   }
diff --git a/libheif/api/libheif/heif_image.h b/libheif/api/libheif/heif_image.h
index a4b13215..b5bcdf6e 100644
--- a/libheif/api/libheif/heif_image.h
+++ b/libheif/api/libheif/heif_image.h
@@ -232,6 +232,27 @@ int heif_image_get_primary_width(const heif_image* img);
 LIBHEIF_API
 int heif_image_get_primary_height(const heif_image* img);

+/**
+ * Crop the image in place by removing margins from each edge.
+ *
+ * The four parameters specify the number of pixels to remove from each side,
+ * not absolute pixel coordinates. For example, to crop a 100x100 image down
+ * to its central 80x80 region, pass `left=10, right=10, top=10, bottom=10`.
+ * Passing all zeros leaves the image unchanged.
+ *
+ * The resulting image has dimensions `(w - left - right) x (h - top - bottom)`,
+ * which must be at least 1x1. All four values must be non-negative and the
+ * sums `left + right` and `top + bottom` must each be strictly less than the
+ * corresponding image dimension; otherwise `heif_error_Usage_error` /
+ * `heif_suberror_Invalid_parameter_value` is returned and the image is left
+ * unchanged.
+ *
+ * @param img    the image to crop (modified in place on success)
+ * @param left   number of pixels to remove from the left edge
+ * @param right  number of pixels to remove from the right edge
+ * @param top    number of pixels to remove from the top edge
+ * @param bottom number of pixels to remove from the bottom edge
+ */
 LIBHEIF_API
 heif_error heif_image_crop(heif_image* img,
                            int left, int right, int top, int bottom);
diff --git a/libheif/image/pixelimage.cc b/libheif/image/pixelimage.cc
index 43eaddcf..6d220f8b 100644
--- a/libheif/image/pixelimage.cc
+++ b/libheif/image/pixelimage.cc
@@ -1452,6 +1452,15 @@ Result<std::shared_ptr<HeifPixelImage>> HeifPixelImage::crop(uint32_t left, uint
   //   Either translate / resample these structures to the crop region, or
   //   return an error when the crop would invalidate them.

+  // (left, right, top, bottom) are coordinate endpoints of the kept region.
+  // Reject inverted or out-of-bounds rectangles so the unsigned arithmetic
+  // below cannot underflow into a multi-GB memcpy (issue #1746).
+  if (right < left || bottom < top || right >= m_width || bottom >= m_height) {
+    return Error{heif_error_Usage_error,
+                 heif_suberror_Invalid_parameter_value,
+                 "Invalid crop region"};
+  }
+
   // --- for some subsampled chroma colorspaces, we have to transform to 4:4:4 before cropping

   bool need_conversion = false;