From be6aadb38471bd4297ebd5172feafe5adfc59bad Mon Sep 17 00:00:00 2001 From: Naveed Khan Date: Tue, 13 Oct 2026 23:45:33 +0530 Subject: [PATCH] fix RectT::IsSame to compare height for equality IsSame compared the height with `<=` instead of `==`, so a rect that is shorter or taller than the reference was still reported as the same rect. The APNG decoder validates each fcTL frame viewport with `raw_viewport.Intersection(image_rect).IsSame(raw_viewport)`: the clipped height is always <= the original, so a frame whose viewport extended past the image bottom passed the bounds check and finalize_frame then read `frameRaw.rows[y]` beyond the decoded rows. --- lib/base/rect.h | 2 +- lib/base/rect_test.cc | 40 ++++++++++++++++++++++++++++++++++++++++ lib/jpegli_lists.cmake | 1 + 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 lib/base/rect_test.cc diff --git a/lib/base/rect.h b/lib/base/rect.h index 16ac425d..58a7a25a 100644 --- a/lib/base/rect.h +++ b/lib/base/rect.h @@ -110,7 +110,7 @@ class RectT { bool IsSame(const RectT& other) const { return x0_ == other.x0_ && xsize_ == other.xsize_ && y0_ == other.y0_ && - ysize_ <= other.ysize_; + ysize_ == other.ysize_; } // Returns true if this Rect fully resides in the given image. ImageT could be diff --git a/lib/base/rect_test.cc b/lib/base/rect_test.cc new file mode 100644 index 00000000..44af327f --- /dev/null +++ b/lib/base/rect_test.cc @@ -0,0 +1,40 @@ +// Copyright (c) the JPEG XL Project Authors. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "lib/base/rect.h" + +#include + +#include "lib/base/testing.h" + +namespace jpegli { +namespace { + +TEST(RectTest, IsSameRequiresEqualSize) { + const RectT base(0, 0, 16, 16); + EXPECT_TRUE(base.IsSame(RectT(0, 0, 16, 16))); + EXPECT_FALSE(base.IsSame(RectT(1, 0, 16, 16))); + EXPECT_FALSE(base.IsSame(RectT(0, 1, 16, 16))); + EXPECT_FALSE(base.IsSame(RectT(0, 0, 8, 16))); + // A rect that is shorter or taller than `other` is not the same rect. The + // height comparison must be an equality, not `<=`. + EXPECT_FALSE(base.IsSame(RectT(0, 0, 16, 8))); + EXPECT_FALSE(base.IsSame(RectT(0, 0, 16, 32))); +} + +// Mirrors the APNG fcTL viewport check in third_party/apngdis/dec.cc: a frame +// whose viewport extends past the image bottom must not be treated as fully +// inside the image, otherwise later per-row copies read out of bounds. +TEST(RectTest, IntersectionIsSameRejectsOversizedHeight) { + const RectT image(0, 0, 16, 16); + const RectT inside(0, 0, 16, 16); + const RectT too_tall(0, 0, 16, 100); + EXPECT_TRUE(inside.Intersection(image).IsSame(inside)); + EXPECT_FALSE(too_tall.Intersection(image).IsSame(too_tall)); +} + +} // namespace +} // namespace jpegli diff --git a/lib/jpegli_lists.cmake b/lib/jpegli_lists.cmake index 9535e26e..8edaa21b 100644 --- a/lib/jpegli_lists.cmake +++ b/lib/jpegli_lists.cmake @@ -241,6 +241,7 @@ set(JPEGLI_INTERNAL_TESTLIB_FILES ) set(JPEGLI_INTERNAL_TESTS + base/rect_test.cc cms/tone_mapping_test.cc cms/transfer_functions_test.cc extras/butteraugli_test.cc