diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c index 8a0b4fb137b8..b08cc64aa30d 100644 --- a/ext/gd/libgd/gd_interpolation.c +++ b/ext/gd/libgd/gd_interpolation.c @@ -919,21 +919,29 @@ static inline LineContribType *_gdContributionsCalc(unsigned int line_size, unsi return res; } +/* Convert a double to an unsigned char, rounding to the nearest + * integer and clamping the result between 0 and max. The absolute + * value of clr must be less than the maximum value of an unsigned + * short. */ static inline unsigned char -uchar_clamp(double clr) { +uchar_clamp(double clr, unsigned char max) { unsigned short result; - assert(fabs(clr) <= SHRT_MAX); + + //assert(fabs(clr) <= SHRT_MAX); + /* Casting a negative float to an unsigned short is undefined. * However, casting a float to a signed truncates toward zero and * casting a negative signed value to an unsigned of the same size * results in a bit-identical value (assuming twos-complement * arithmetic). This is what we want: all legal negative values * for clr will be greater than 255. */ + /* Convert and clamp. */ result = (unsigned short)(short)(clr + 0.5); - if (result > 255) { - result = (clr < 0) ? 0 : 255; + if (result > max) { + result = (clr < 0) ? 0 : max; }/* if */ + return result; }/* uchar_clamp*/ @@ -957,7 +965,9 @@ static inline void _gdScaleRow(gdImagePtr pSrc, unsigned int src_width, gdImage b += contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetBlue(p_src_row[i])); a += contrib->ContribRow[x].Weights[left_channel] * (double)(gdTrueColorGetAlpha(p_src_row[i])); } - p_dst_row[x] = gdTrueColorAlpha(uchar_clamp(r), uchar_clamp(g), uchar_clamp(b), uchar_clamp(a)); + p_dst_row[x] = gdTrueColorAlpha(uchar_clamp(r, 0xFF), uchar_clamp(g, 0xFF), + uchar_clamp(b, 0xFF), + uchar_clamp(a, 0x7F)); /* alpha is 0..127 */ } } @@ -1004,7 +1014,9 @@ static inline void _gdScaleCol (gdImagePtr pSrc, unsigned int src_width, gdImag b += contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetBlue(pCurSrc)); a += contrib->ContribRow[y].Weights[i_iLeft] * (double)(gdTrueColorGetAlpha(pCurSrc)); } - pRes->tpixels[y][uCol] = gdTrueColorAlpha(uchar_clamp(r), uchar_clamp(g), uchar_clamp(b), uchar_clamp(a)); + pRes->tpixels[y][uCol] = gdTrueColorAlpha(uchar_clamp(r, 0xFF), uchar_clamp(g, 0xFF), + uchar_clamp(b, 0xFF), + uchar_clamp(a, 0x7F)); /* alpha is 0..127 */ } } diff --git a/ext/gd/tests/gh16559.phpt b/ext/gd/tests/gh16559.phpt new file mode 100644 index 000000000000..4481311c4c45 --- /dev/null +++ b/ext/gd/tests/gh16559.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-16559 (UBSan abort in ext/gd/libgd/gd_interpolation.c:1007) +--EXTENSIONS-- +gd +--FILE-- + +--EXPECT-- +object(GdImage)#2 (0) { +}