aom_img_flip: fix chroma height calculation Round chroma height up for odd display heights to prevent OOB read. Bug: 541725398 Fixed: 541725398 Change-Id: I6b85e6d6548b89beb40e3e116cbd34417daf9a4a
diff --git a/aom/src/aom_image.c b/aom/src/aom_image.c index f4fdb28..881429a 100644 --- a/aom/src/aom_image.c +++ b/aom/src/aom_image.c
@@ -293,21 +293,31 @@ } void aom_img_flip(aom_image_t *img) { + const unsigned int chroma_height = + (img->d_h + img->y_chroma_shift) >> img->y_chroma_shift; + /* Note: In the pointer adjustment calculations, we want the rhs to be * promoted to a signed type. Section 6.3.1.8 of the ISO C99 standard * indicates that if the first operand of the multiplication is unsigned, the * stride will be promoted to unsigned, causing errors when the lhs is a * larger type than the rhs. */ - img->planes[AOM_PLANE_Y] += (signed)(img->d_h - 1) * img->stride[AOM_PLANE_Y]; + if (img->planes[AOM_PLANE_Y]) { + img->planes[AOM_PLANE_Y] += + (signed)(img->d_h - 1) * img->stride[AOM_PLANE_Y]; + } img->stride[AOM_PLANE_Y] = -img->stride[AOM_PLANE_Y]; - img->planes[AOM_PLANE_U] += (signed)((img->d_h >> img->y_chroma_shift) - 1) * - img->stride[AOM_PLANE_U]; + if (img->planes[AOM_PLANE_U]) { + img->planes[AOM_PLANE_U] += + (signed)(chroma_height - 1) * img->stride[AOM_PLANE_U]; + } img->stride[AOM_PLANE_U] = -img->stride[AOM_PLANE_U]; - img->planes[AOM_PLANE_V] += (signed)((img->d_h >> img->y_chroma_shift) - 1) * - img->stride[AOM_PLANE_V]; + if (img->planes[AOM_PLANE_V]) { + img->planes[AOM_PLANE_V] += + (signed)(chroma_height - 1) * img->stride[AOM_PLANE_V]; + } img->stride[AOM_PLANE_V] = -img->stride[AOM_PLANE_V]; }
diff --git a/test/aom_image_test.cc b/test/aom_image_test.cc index 6c0059b..e10c9ad 100644 --- a/test/aom_image_test.cc +++ b/test/aom_image_test.cc
@@ -141,3 +141,79 @@ aom_img_free(image); } } + +TEST(AomImageTest, AomImgFlipNoAlpha) { + aom_image_t *img = aom_img_alloc(nullptr, AOM_IMG_FMT_I420, 64, 64, 16); + ASSERT_NE(img, nullptr); + aom_img_flip(img); + aom_img_free(img); +} + +TEST(AomImageTest, AomImgFlipOneRow) { + aom_image_t *img = aom_img_alloc(nullptr, AOM_IMG_FMT_I420, 16, 1, 1); + ASSERT_NE(img, nullptr); + unsigned char *const y_plane = img->planes[AOM_PLANE_Y]; + unsigned char *const u_plane = img->planes[AOM_PLANE_U]; + unsigned char *const v_plane = img->planes[AOM_PLANE_V]; + const int y_stride = img->stride[AOM_PLANE_Y]; + const int u_stride = img->stride[AOM_PLANE_U]; + const int v_stride = img->stride[AOM_PLANE_V]; + + aom_img_flip(img); + + EXPECT_EQ(img->planes[AOM_PLANE_Y], y_plane); + EXPECT_EQ(img->planes[AOM_PLANE_U], u_plane); + EXPECT_EQ(img->planes[AOM_PLANE_V], v_plane); + EXPECT_EQ(img->stride[AOM_PLANE_Y], -y_stride); + EXPECT_EQ(img->stride[AOM_PLANE_U], -u_stride); + EXPECT_EQ(img->stride[AOM_PLANE_V], -v_stride); + + aom_img_flip(img); + + EXPECT_EQ(img->planes[AOM_PLANE_Y], y_plane); + EXPECT_EQ(img->planes[AOM_PLANE_U], u_plane); + EXPECT_EQ(img->planes[AOM_PLANE_V], v_plane); + EXPECT_EQ(img->stride[AOM_PLANE_Y], y_stride); + EXPECT_EQ(img->stride[AOM_PLANE_U], u_stride); + EXPECT_EQ(img->stride[AOM_PLANE_V], v_stride); + + aom_img_free(img); +} + +TEST(AomImageTest, AomImgFlipOddHeight) { + static constexpr aom_img_fmt_t kFormats[] = { + AOM_IMG_FMT_YV12, AOM_IMG_FMT_I420, AOM_IMG_FMT_NV12, + AOM_IMG_FMT_I42016, AOM_IMG_FMT_YV1216, + }; + + for (const aom_img_fmt_t format : kFormats) { + aom_image_t *img = aom_img_alloc(nullptr, format, 16, 3, 1); + ASSERT_NE(img, nullptr); + unsigned char *const y_plane = img->planes[AOM_PLANE_Y]; + unsigned char *const u_plane = img->planes[AOM_PLANE_U]; + unsigned char *const v_plane = img->planes[AOM_PLANE_V]; + const int y_stride = img->stride[AOM_PLANE_Y]; + const int u_stride = img->stride[AOM_PLANE_U]; + const int v_stride = img->stride[AOM_PLANE_V]; + + aom_img_flip(img); + + EXPECT_EQ(img->planes[AOM_PLANE_Y], y_plane + 2 * y_stride); + EXPECT_EQ(img->planes[AOM_PLANE_U], u_plane + u_stride); + EXPECT_EQ(img->planes[AOM_PLANE_V], v_plane + v_stride); + EXPECT_EQ(img->stride[AOM_PLANE_Y], -y_stride); + EXPECT_EQ(img->stride[AOM_PLANE_U], -u_stride); + EXPECT_EQ(img->stride[AOM_PLANE_V], -v_stride); + + aom_img_flip(img); + + EXPECT_EQ(img->planes[AOM_PLANE_Y], y_plane); + EXPECT_EQ(img->planes[AOM_PLANE_U], u_plane); + EXPECT_EQ(img->planes[AOM_PLANE_V], v_plane); + EXPECT_EQ(img->stride[AOM_PLANE_Y], y_stride); + EXPECT_EQ(img->stride[AOM_PLANE_U], u_stride); + EXPECT_EQ(img->stride[AOM_PLANE_V], v_stride); + + aom_img_free(img); + } +}