diff --git a/source/scale_argb.cc b/source/scale_argb.cc index 1c376e93f..9c2ac29c9 100644 --- a/source/scale_argb.cc +++ b/source/scale_argb.cc @@ -404,25 +404,23 @@ static int ScaleARGBBilinearDown(int src_width, if (!row) return 1; - const int max_y = (src_height - 1) << 16; - if (y > max_y) { - y = max_y; - } + const int64_t max_y = (int64_t)(src_height - 1) << 16; + int64_t y64 = y; for (j = 0; j < dst_height; ++j) { - int yi = y >> 16; + if (y64 > max_y) { + y64 = max_y; + } + int yi = (int)(y64 >> 16); const uint8_t* src = src_argb + yi * src_stride; if (filtering == kFilterLinear) { ScaleARGBFilterCols(dst_argb, src, dst_width, x, dx); } else { - int yf = (y >> 8) & 255; + int yf = (int)((y64 >> 8) & 255); InterpolateRow(row, src, src_stride, clip_src_width, yf); ScaleARGBFilterCols(dst_argb, row, dst_width, x, dx); } dst_argb += dst_stride; - y += dy; - if (y > max_y) { - y = max_y; - } + y64 += dy; } free_aligned_buffer_64(row); } @@ -450,7 +448,7 @@ static int ScaleARGBBilinearUp(int src_width, void (*ScaleARGBFilterCols)(uint8_t* dst_argb, const uint8_t* src_argb, int dst_width, int x, int dx) = filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C; - const int max_y = (src_height - 1) << 16; + const int64_t max_y = (int64_t)(src_height - 1) << 16; #if defined(HAS_INTERPOLATEROW_AVX2) if (TestCpuFlag(kCpuHasAVX2)) { InterpolateRow = InterpolateRow_Any_AVX2; @@ -550,12 +548,13 @@ static int ScaleARGBBilinearUp(int src_width, #endif } - if (y > max_y) { - y = max_y; + int64_t y64 = y; + if (y64 > max_y) { + y64 = max_y; } { - int yi = y >> 16; + int yi = (int)(y64 >> 16); const uint8_t* src = src_argb + yi * src_stride; // Allocate 2 rows of ARGB. @@ -578,31 +577,27 @@ static int ScaleARGBBilinearUp(int src_width, } for (j = 0; j < dst_height; ++j) { - yi = y >> 16; + if (y64 > max_y) { + y64 = max_y; + } + yi = (int)(y64 >> 16); if (yi != lasty) { - if (y > max_y) { - y = max_y; - yi = y >> 16; - src = src_argb + yi * src_stride; - } - if (yi != lasty) { - ScaleARGBFilterCols(rowptr, src, dst_width, x, dx); - rowptr += rowstride; - rowstride = -rowstride; - lasty = yi; - if ((y + 65536) < max_y) { - src += src_stride; - } + ScaleARGBFilterCols(rowptr, src, dst_width, x, dx); + rowptr += rowstride; + rowstride = -rowstride; + lasty = yi; + if ((y64 + 65536) < max_y) { + src += src_stride; } } if (filtering == kFilterLinear) { InterpolateRow(dst_argb, rowptr, 0, dst_width * 4, 0); } else { - int yf = (y >> 8) & 255; + int yf = (int)((y64 >> 8) & 255); InterpolateRow(dst_argb, rowptr, rowstride, dst_width * 4, yf); } dst_argb += dst_stride; - y += dy; + y64 += dy; } free_aligned_buffer_64(row); } @@ -630,7 +625,7 @@ static void ScaleARGBSimple(int src_width, void (*ScaleARGBCols)(uint8_t* dst_argb, const uint8_t* src_argb, int dst_width, int x, int dx) = (src_width >= 32768) ? ScaleARGBCols64_C : ScaleARGBCols_C; - (void)src_height; + const int64_t max_y = (int64_t)(src_height - 1) << 16; #if defined(HAS_SCALEARGBCOLS_SSE2) if (TestCpuFlag(kCpuHasSSE2) && src_width < 32768) { ScaleARGBCols = ScaleARGBCols_SSE2; @@ -661,11 +656,15 @@ static void ScaleARGBSimple(int src_width, #endif } + int64_t y64 = y; for (j = 0; j < dst_height; ++j) { - ScaleARGBCols(dst_argb, src_argb + (y >> 16) * src_stride, dst_width, x, + if (y64 > max_y) { + y64 = max_y; + } + ScaleARGBCols(dst_argb, src_argb + (y64 >> 16) * src_stride, dst_width, x, dx); dst_argb += dst_stride; - y += dy; + y64 += dy; } } diff --git a/source/scale_common.cc b/source/scale_common.cc index ce8843c3b..d0b0edd95 100644 --- a/source/scale_common.cc +++ b/source/scale_common.cc @@ -1474,7 +1474,9 @@ void ScalePlaneVertical(int src_height, void (*InterpolateRow)(uint8_t* dst_argb, const uint8_t* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_C; - const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0; + const int64_t max_y = + (src_height > 1) ? (((int64_t)src_height - 1) << 16) - 1 : 0; + int64_t y64 = y; int j; assert(bpp >= 1 && bpp <= 4); assert(src_height != 0); @@ -1524,15 +1526,15 @@ void ScalePlaneVertical(int src_height, for (j = 0; j < dst_height; ++j) { int yi; int yf; - if (y > max_y) { - y = max_y; + if (y64 > max_y) { + y64 = max_y; } - yi = y >> 16; - yf = filtering ? ((y >> 8) & 255) : 0; + yi = (int)(y64 >> 16); + yf = filtering ? (int)((y64 >> 8) & 255) : 0; InterpolateRow(dst_argb, src_argb + yi * (ptrdiff_t)src_stride, src_stride, dst_width_bytes, yf); dst_argb += dst_stride; - y += dy; + y64 += dy; } } @@ -1553,7 +1555,9 @@ void ScalePlaneVertical_16(int src_height, void (*InterpolateRow)(uint16_t* dst_argb, const uint16_t* src_argb, ptrdiff_t src_stride, int dst_width, int source_y_fraction) = InterpolateRow_16_C; - const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0; + const int64_t max_y = + (src_height > 1) ? (((int64_t)src_height - 1) << 16) - 1 : 0; + int64_t y64 = y; int j; assert(wpp >= 1 && wpp <= 2); assert(src_height != 0); @@ -1592,15 +1596,15 @@ void ScalePlaneVertical_16(int src_height, for (j = 0; j < dst_height; ++j) { int yi; int yf; - if (y > max_y) { - y = max_y; + if (y64 > max_y) { + y64 = max_y; } - yi = y >> 16; - yf = filtering ? ((y >> 8) & 255) : 0; + yi = (int)(y64 >> 16); + yf = filtering ? (int)((y64 >> 8) & 255) : 0; InterpolateRow(dst_argb, src_argb + yi * (ptrdiff_t)src_stride, src_stride, dst_width_words, yf); dst_argb += dst_stride; - y += dy; + y64 += dy; } } diff --git a/unit_test/scale_argb_test.cc b/unit_test/scale_argb_test.cc index 3d3e36fc5..09b23698b 100644 --- a/unit_test/scale_argb_test.cc +++ b/unit_test/scale_argb_test.cc @@ -597,4 +597,42 @@ TEST_F(LibYUVScaleTest, ARGBTest4x) { free_aligned_buffer_page_end(orig_pixels); } +TEST_F(LibYUVScaleTest, ARGBScale_LargeHeightOverflow) { + const int src_w = 4; + const int src_h = 32767; + align_buffer_page_end(orig_pixels, src_w * src_h * 4); + align_buffer_page_end(dest_pixels, src_w * 2 * 4); + memset(orig_pixels, 128, src_w * src_h * 4); + + // Test both vertical-only scaling (dst_w == src_w) and 2D scaling (dst_w != src_w). + for (int dst_w : {4, 2}) { + int res = ARGBScale(orig_pixels, src_w * 4, src_w, src_h, dest_pixels, + dst_w * 4, dst_w, 2, kFilterBilinear); + EXPECT_EQ(0, res); + + res = ARGBScale(orig_pixels, src_w * 4, src_w, -src_h, dest_pixels, + dst_w * 4, dst_w, 2, kFilterBilinear); + EXPECT_EQ(0, res); + + res = ARGBScale(orig_pixels, src_w * 4, src_w, src_h, dest_pixels, + dst_w * 4, dst_w, 2, kFilterLinear); + EXPECT_EQ(0, res); + + res = ARGBScale(orig_pixels, src_w * 4, src_w, -src_h, dest_pixels, + dst_w * 4, dst_w, 2, kFilterLinear); + EXPECT_EQ(0, res); + + res = ARGBScale(orig_pixels, src_w * 4, src_w, src_h, dest_pixels, + dst_w * 4, dst_w, 2, kFilterNone); + EXPECT_EQ(0, res); + + res = ARGBScale(orig_pixels, src_w * 4, src_w, -src_h, dest_pixels, + dst_w * 4, dst_w, 2, kFilterNone); + EXPECT_EQ(0, res); + } + + free_aligned_buffer_page_end(dest_pixels); + free_aligned_buffer_page_end(orig_pixels); +} + } // namespace libyuv