Port "improve _gdImageFillTiled() internal function" (GH-17356)

This improvement was done for libgd 2.1.0[1], and the erroneous
calculation has been fixed as of libgd 2.2.0[2].

While we're at it we also add the overflow checks of external libgd;
these are not really necessary, since `.sx * .sy` overflow was already
prevented when the image has been created, and since we're using
`safe_emalloc()` the `struct seg` overflow is also prevented.  It
should be noted that `overflow2()` prevents `int` overflow, while
`safe_emalloc()` prevents `size_t` overflow, so the former is more
restrictive.  For parity with external libgd, this still appears to be
a good thing.

[1] <86a5debede>
[2] <e87ec88e1c>
This commit is contained in:
Christoph M. Becker 2025-01-07 01:23:05 +01:00 committed by GitHub
parent d20880ce3b
commit 2c49f52b0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -2026,6 +2026,14 @@ void gdImageFill(gdImagePtr im, int x, int y, int nc)
goto done; goto done;
} }
if(overflow2(im->sy, im->sx)) {
return;
}
if(overflow2(sizeof(struct seg), ((im->sy * im->sx) / 4))) {
return;
}
stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1); stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
sp = stack; sp = stack;
@ -2073,13 +2081,13 @@ done:
static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc) static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
{ {
int i, l, x1, x2, dy; int l, x1, x2, dy;
int oc; /* old pixel value */ int oc; /* old pixel value */
int wx2,wy2; int wx2,wy2;
/* stack of filled segments */ /* stack of filled segments */
struct seg *stack; struct seg *stack;
struct seg *sp; struct seg *sp;
char **pts; char *pts;
if (!im->tile) { if (!im->tile) {
return; return;
@ -2089,11 +2097,16 @@ static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
nc = gdImageTileGet(im,x,y); nc = gdImageTileGet(im,x,y);
pts = (char **) ecalloc(im->sy + 1, sizeof(char *)); if(overflow2(im->sy, im->sx)) {
for (i = 0; i < im->sy + 1; i++) { return;
pts[i] = (char *) ecalloc(im->sx + 1, sizeof(char));
} }
if(overflow2(sizeof(struct seg), ((im->sy * im->sx) / 4))) {
return;
}
pts = (char *) ecalloc(im->sy * im->sx, sizeof(char));
stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1); stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
sp = stack; sp = stack;
@ -2105,9 +2118,9 @@ static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
FILL_PUSH(y+1, x, x, -1); FILL_PUSH(y+1, x, x, -1);
while (sp>stack) { while (sp>stack) {
FILL_POP(y, x1, x2, dy); FILL_POP(y, x1, x2, dy);
for (x=x1; x>=0 && (!pts[y][x] && gdImageGetPixel(im,x,y)==oc); x--) { for (x=x1; x>=0 && (!pts[y + x*wy2] && gdImageGetPixel(im,x,y)==oc); x--) {
nc = gdImageTileGet(im,x,y); nc = gdImageTileGet(im,x,y);
pts[y][x] = 1; pts[y + x*wy2] = 1;
gdImageSetPixel(im,x, y, nc); gdImageSetPixel(im,x, y, nc);
} }
if (x>=x1) { if (x>=x1) {
@ -2121,9 +2134,9 @@ static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
} }
x = x1+1; x = x1+1;
do { do {
for(; x<wx2 && (!pts[y][x] && gdImageGetPixel(im,x, y)==oc); x++) { for(; x<wx2 && (!pts[y + x*wy2] && gdImageGetPixel(im,x, y)==oc); x++) {
nc = gdImageTileGet(im,x,y); nc = gdImageTileGet(im,x,y);
pts[y][x] = 1; pts[y + x * wy2] = 1;
gdImageSetPixel(im, x, y, nc); gdImageSetPixel(im, x, y, nc);
} }
FILL_PUSH(y, l, x-1, dy); FILL_PUSH(y, l, x-1, dy);
@ -2132,15 +2145,11 @@ static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
FILL_PUSH(y, x2+1, x-1, -dy); FILL_PUSH(y, x2+1, x-1, -dy);
} }
skip: skip:
for(x++; x<=x2 && (pts[y][x] || gdImageGetPixel(im,x, y)!=oc); x++); for(x++; x<=x2 && (pts[y + x*wy2] || gdImageGetPixel(im,x, y)!=oc); x++);
l = x; l = x;
} while (x<=x2); } while (x<=x2);
} }
for(i = 0; i < im->sy + 1; i++) {
efree(pts[i]);
}
efree(pts); efree(pts);
efree(stack); efree(stack);
} }