Avoid integer overflow when calculating reduced image size - #9904
Conversation
|
|
||
| imOut = ImagingNewDirty( | ||
| imIn->mode, (box[2] + xscale - 1) / xscale, (box[3] + yscale - 1) / yscale | ||
| imIn->mode, (box[2] - 1) / xscale + 1, (box[3] - 1) / yscale + 1 |
There was a problem hiding this comment.
I'd maybe add a comment here about the operation order, and that it guarantees the image to have at least size 1x1.
There was a problem hiding this comment.
Added in bf60f3c.
While checking this I noticed that xscale * yscale in ImagingReduceNxN and (box[2] % xscale) * yscale in ImagingReduceCorners still overflow with a factor this large. Those values only feed loops that run zero iterations, so the output pixels are correct and no bad memory access happens, but an instrumented build will still report the overflow on the same input. Clamping both scales to the box size after the size calculation would remove it.
I am happy to add that here, or to keep this PR to the crash and raise it separately.
There was a problem hiding this comment.
What do you mean with "Those values only feed loops that run zero iterations"? Those functions probably shouldn't end up being called...
In fact, it could be a good idea to add separate paths when the reduction ends up being one-dimensional in one dimension or the other, or both, since isn't the end result then just an average over rows, columns or both (separable)?
ImagingReduce()sizes the output image with(box[2] + xscale - 1) / xscale. When the box width plus the scale exceedsINT_MAXthat addition overflows and the result is a zero-width, zero-height image.ImagingReduceCorners()then writes toimOut->image8[0][0], which has no rows allocated, soImage.new("L", (4, 4)).reduce(2**31 - 1)segfaults.Since the box is never empty, the same round-up can be written as
(box[2] - 1) / xscale + 1, which cannot overflow and gives a 1x1 image as expected.Fixes #9903