Commit cb8f7bd434e for php.net
commit cb8f7bd434ec3387138cc6c68cae17fed71c2b65
Author: David Carlier <devnexen@gmail.com>
Date: Mon May 25 19:30:37 2026 +0100
Fix GH-19730: undefined behavior in gd_interpolation.c.
Port libgd f6202ec0de1c8340cf9b69c4a86c84fc63703207: validate the
computed bounding box in gdTransformAffineBoundingBox before casting
the floating-point coordinates to int, and propagate the failure
through gdTransformAffineGetImage.
close GH-22149
diff --git a/NEWS b/NEWS
index 3899aea32ca..dbf83143dce 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,8 @@ PHP NEWS
(David Carlier)
. Fixed bug GH-19739 (imageellipse/imagefilledellipse overflow).
(David Carlier)
+ . Fixed bug GH-19730 (imageaffine overflow).
+ (David Carlier)
- Intl:
. Fix incorrect argument positions for uninitialized calendar arguments in
diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c
index b3f391e6d20..7b3824ca1eb 100644
--- a/ext/gd/libgd/gd_interpolation.c
+++ b/ext/gd/libgd/gd_interpolation.c
@@ -57,6 +57,7 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include <limits.h>
#include "gd.h"
#include "gdhelpers.h"
@@ -2245,7 +2246,10 @@ int gdTransformAffineGetImage(gdImagePtr *dst,
src_area = &area_full;
}
- gdTransformAffineBoundingBox(src_area, affine, &bbox);
+ if (gdTransformAffineBoundingBox(src_area, affine, &bbox) != GD_TRUE) {
+ *dst = NULL;
+ return GD_FALSE;
+ }
*dst = gdImageCreateTrueColor(bbox.width, bbox.height);
if (*dst == NULL) {
@@ -2421,6 +2425,8 @@ int gdTransformAffineCopy(gdImagePtr dst,
int gdTransformAffineBoundingBox(gdRectPtr src, const double affine[6], gdRectPtr bbox)
{
gdPointF extent[4], min, max, point;
+ double width, height;
+ int bbox_x, bbox_y, bbox_width, bbox_height;
int i;
extent[0].x=0.0;
@@ -2451,10 +2457,29 @@ int gdTransformAffineBoundingBox(gdRectPtr src, const double affine[6], gdRectPt
if (max.y < extent[i].y)
max.y=extent[i].y;
}
- bbox->x = (int) min.x;
- bbox->y = (int) min.y;
- bbox->width = (int) floor(max.x - min.x) - 1;
- bbox->height = (int) floor(max.y - min.y);
+ width = floor(max.x - min.x);
+ height = floor(max.y - min.y);
+ if (!isfinite(min.x) || !isfinite(min.y) || !isfinite(width) || !isfinite(height)
+ || min.x <= INT_MIN || min.x > INT_MAX
+ || min.y <= INT_MIN || min.y > INT_MAX
+ || width < 1.0 || width > INT_MAX
+ || height < 0.0 || height > INT_MAX) {
+ return GD_FALSE;
+ }
+ bbox_x = (int) min.x;
+ bbox_y = (int) min.y;
+ bbox_width = (int) width - 1;
+ bbox_height = (int) height;
+ if ((bbox_x < 0 && bbox_width > INT_MAX + bbox_x)
+ || (bbox_x > 0 && bbox_width > INT_MAX - bbox_x)
+ || (bbox_y < 0 && bbox_height > INT_MAX + bbox_y)
+ || (bbox_y > 0 && bbox_height > INT_MAX - bbox_y)) {
+ return GD_FALSE;
+ }
+ bbox->x = bbox_x;
+ bbox->y = bbox_y;
+ bbox->width = bbox_width;
+ bbox->height = bbox_height;
return GD_TRUE;
}
diff --git a/ext/gd/tests/gh19730.phpt b/ext/gd/tests/gh19730.phpt
new file mode 100644
index 00000000000..5ea4a2846a9
--- /dev/null
+++ b/ext/gd/tests/gh19730.phpt
@@ -0,0 +1,18 @@
+--TEST--
+GH-19730 (undefined behavior in gd_interpolation.c)
+--EXTENSIONS--
+gd
+--SKIPIF--
+<?php
+ if (!GD_BUNDLED) {
+ die("skip meaningful only for bundled libgd\n");
+ }
+?>
+--FILE--
+<?php
+$im = imagecreatetruecolor(8, 8);
+$affine = [1211472000, 1, 1, 1, 1, 1];
+var_dump(imageaffine($im, $affine));
+?>
+--EXPECT--
+bool(false)