From 5c1e5991d44462055f39dd0d5f5b807bd2fc1d28 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 29 Sep 2026 00:10:43 +1000 Subject: [PATCH 1/3] Return 0 or -1 from ImagingTransform() --- src/_imaging.c | 6 +++--- src/libImaging/Geometry.c | 36 +++++++++++++++++++++--------------- src/libImaging/Imaging.h | 2 +- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/_imaging.c b/src/_imaging.c index cc782698245..8eba25970b1 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -2042,7 +2042,7 @@ _resize(ImagingObject *self, PyObject *args) { imOut = ImagingNewDirty(imIn->mode, xsize, ysize); - imOut = ImagingTransform( + ImagingTransform( imOut, imIn, IMAGING_TRANSFORM_AFFINE, 0, 0, xsize, ysize, a, filter, 1 ); } else { @@ -2167,13 +2167,13 @@ _transform(ImagingObject *self, PyObject *args) { return NULL; } - imOut = ImagingTransform( + int error = ImagingTransform( self->image, imagep->image, method, x0, y0, x1, y1, a, filter, fill ); free(a); - if (!imOut) { + if (error) { return NULL; } diff --git a/src/libImaging/Geometry.c b/src/libImaging/Geometry.c index 198cad43bf2..aa4fd655ffb 100644 --- a/src/libImaging/Geometry.c +++ b/src/libImaging/Geometry.c @@ -779,7 +779,7 @@ getfilter(Imaging im, int filterid) { /* transformation engines */ -Imaging +int ImagingGenericTransform( Imaging imOut, Imaging imIn, @@ -801,12 +801,14 @@ ImagingGenericTransform( double xx, yy; if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + ImagingError_ModeError(); + return -1; } ImagingTransformFilter filter = getfilter(imIn, filterid); if (!filter) { - return (Imaging)ImagingError_ValueError("bad filter number"); + ImagingError_ValueError("bad filter number"); + return -1; } ImagingCopyPalette(imOut, imIn); @@ -841,10 +843,10 @@ ImagingGenericTransform( ImagingSectionLeave(&cookie); - return imOut; + return 0; } -static Imaging +static int ImagingScaleAffine( Imaging imOut, Imaging imIn, int x0, int y0, int x1, int y1, double a[6], int fill ) { @@ -858,7 +860,8 @@ ImagingScaleAffine( int *xintab; if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + ImagingError_ModeError(); + return -1; } ImagingCopyPalette(imOut, imIn); @@ -883,7 +886,8 @@ ImagingScaleAffine( xintab = (int *)calloc(out_xsize, sizeof(int)); if (!xintab) { ImagingDelete(imOut); - return (Imaging)ImagingError_MemoryError(); + ImagingError_MemoryError(); + return -1; } xo = a[2] + a[0] * 0.5; @@ -936,7 +940,7 @@ ImagingScaleAffine( free(xintab); - return imOut; + return 0; } static inline int @@ -947,7 +951,7 @@ check_fixed(double a[6], int x, int y) { ); } -static inline Imaging +static inline int affine_fixed( Imaging imOut, Imaging imIn, @@ -1022,10 +1026,10 @@ affine_fixed( #undef AFFINE_TRANSFORM_FIXED - return imOut; + return 0; } -Imaging +int ImagingTransformAffine( Imaging imOut, Imaging imIn, @@ -1048,7 +1052,8 @@ ImagingTransformAffine( double xo, yo; if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + ImagingError_ModeError(); + return -1; } if (filterid || imIn->type == IMAGING_TYPE_I16) { @@ -1131,10 +1136,10 @@ ImagingTransformAffine( #undef AFFINE_TRANSFORM - return imOut; + return 0; } -Imaging +int ImagingTransform( Imaging imOut, Imaging imIn, @@ -1162,7 +1167,8 @@ ImagingTransform( transform = quad_transform; break; default: - return (Imaging)ImagingError_ValueError("bad transform method"); + ImagingError_ValueError("bad transform method"); + return -1; } return ImagingGenericTransform( diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index 20f74b519a3..455d9c5706f 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -389,7 +389,7 @@ extern Imaging ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]); extern Imaging ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]); -extern Imaging +extern int ImagingTransform( Imaging imOut, Imaging imIn, From aafa6c75f7cdabb9f409a8aac7c780bea31d08d9 Mon Sep 17 00:00:00 2001 From: Jeffrey 'Alex' Clark Date: Fri, 18 Sep 2026 14:20:20 -0400 Subject: [PATCH 2/3] Avoid double free after affine transform allocation failure Stop ImagingScaleAffine() from deleting caller-owned output images when its lookup-table allocation fails. Make _resize() handle its temporary image explicitly so transform failures still clean up safely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/_imaging.c | 12 +++++++++--- src/libImaging/Geometry.c | 1 - 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/_imaging.c b/src/_imaging.c index 8eba25970b1..0ce66d872cd 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -2041,10 +2041,16 @@ _resize(ImagingObject *self, PyObject *args) { a[5] = box[1]; imOut = ImagingNewDirty(imIn->mode, xsize, ysize); + if (!imOut) { + return NULL; + } - ImagingTransform( - imOut, imIn, IMAGING_TRANSFORM_AFFINE, 0, 0, xsize, ysize, a, filter, 1 - ); + if (ImagingTransform( + imOut, imIn, IMAGING_TRANSFORM_AFFINE, 0, 0, xsize, ysize, a, filter, 1 + )) { + ImagingDelete(imOut); + return NULL; + } } else { imOut = ImagingResample(imIn, xsize, ysize, filter, box); } diff --git a/src/libImaging/Geometry.c b/src/libImaging/Geometry.c index aa4fd655ffb..f1015fc6007 100644 --- a/src/libImaging/Geometry.c +++ b/src/libImaging/Geometry.c @@ -885,7 +885,6 @@ ImagingScaleAffine( /* malloc check ok, uses calloc for overflow */ xintab = (int *)calloc(out_xsize, sizeof(int)); if (!xintab) { - ImagingDelete(imOut); ImagingError_MemoryError(); return -1; } From 167e64be4616a76b4554774948205e7533a0e361 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 1 Oct 2026 15:26:50 +1000 Subject: [PATCH 3/3] Add comment --- src/libImaging/Geometry.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libImaging/Geometry.c b/src/libImaging/Geometry.c index f1015fc6007..37766978651 100644 --- a/src/libImaging/Geometry.c +++ b/src/libImaging/Geometry.c @@ -1138,6 +1138,21 @@ ImagingTransformAffine( return 0; } +/** + * Runs a transformation over the data from imIn, placing the result in imOut. + * + * @param imOut Existing image to write into + * @param imIn Source image to transform + * @param method Which method to use + * @param x0 The left co-ordinate of the area to transform + * @param y0 The upper co-ordinate of the area to transform + * @param x1 The right co-ordinate of the area to transform + * @param y1 The lower co-ordinate of the area to transform + * @param a An array of extra data for the transformation method + * @param filterid Which filter to use + * @param fill 1 to fill the area with zeros + * @return -1 in case of an error, 0 otherwise + */ int ImagingTransform( Imaging imOut,