Commit ac6d2d91 for libheif
commit ac6d2d91be17f730cba833e29791488392f65169
Author: d-polikhranidi <76728763+d-polikhranidi@users.noreply.github.com>
Date: Wed Jul 1 07:54:14 2026 +0300
Fix: parse 'meta' box with size 0 (extends to end of file)
A top-level 'meta' box with size 0 -- which per ISO/IEC 14496-12 clause 4.2
means the box extends to the end of the file (legal for the last box) -- was
rejected outright ("Cannot read meta box with unspecified size"), a
previously-marked TODO in file_layout.cc. Such files are read and rendered by
libavif (Chromium's AVIF decoder), so libheif-based pipelines (ImageMagick,
libvips, sharp) fail on input that browsers display fine.
Resolve size == 0 to the file size via request_range() and parse normally,
matching the end-of-file handling libheif already uses for other boxes. This
is bounded by the file size, so there is no unbounded read.
Adds a regression test (tests/file_layout.cc "meta box with size 0") and a
498-byte fixture (tests/data/meta_size_zero.avif, from libavif's test corpus).
Signed-off-by: d-polikhranidi <76728763+d-polikhranidi@users.noreply.github.com>
diff --git a/libheif/file_layout.cc b/libheif/file_layout.cc
index 042a4190..d66c20a6 100644
--- a/libheif/file_layout.cc
+++ b/libheif/file_layout.cc
@@ -128,20 +128,29 @@ Error FileLayout::read(const std::shared_ptr<StreamReader>& stream, const heif_s
if (box_header.get_short_type() == fourcc("meta")) {
const uint64_t meta_box_start = next_box_start;
- if (box_header.get_box_size() == 0) {
- // TODO: get file-size from stream and compute box size
- return {heif_error_Invalid_input,
- heif_suberror_No_meta_box,
- "Cannot read meta box with unspecified size"};
+ uint64_t end_of_meta_box;
+ if (box_header.get_box_size() == BoxHeader::size_until_end_of_file) {
+ // A box size of 0 means the box extends to the end of the file
+ // (ISO/IEC 14496-12 clause 4.2), which is legal for the last box.
+ // Resolve it to the file size.
+ end_of_meta_box = m_stream_reader->request_range(meta_box_start,
+ std::numeric_limits<uint64_t>::max());
+ m_max_length = end_of_meta_box;
+ if (end_of_meta_box <= meta_box_start) {
+ return {heif_error_Invalid_input,
+ heif_suberror_No_meta_box,
+ "Cannot read meta box with unspecified size"};
+ }
}
-
- uint64_t end_of_meta_box = box_header.get_box_size();
- if (end_of_meta_box > std::numeric_limits<uint64_t>::max() - meta_box_start) {
- return {heif_error_Invalid_input,
- heif_suberror_No_meta_box,
- "Cannot read meta box with invalid size"};
+ else {
+ end_of_meta_box = box_header.get_box_size();
+ if (end_of_meta_box > std::numeric_limits<uint64_t>::max() - meta_box_start) {
+ return {heif_error_Invalid_input,
+ heif_suberror_No_meta_box,
+ "Cannot read meta box with invalid size"};
+ }
+ end_of_meta_box += meta_box_start;
}
- end_of_meta_box += meta_box_start;
if (m_max_length < end_of_meta_box) {
m_max_length = m_stream_reader->request_range(meta_box_start, end_of_meta_box);
}
diff --git a/tests/data/meta_size_zero.avif b/tests/data/meta_size_zero.avif
new file mode 100644
index 00000000..bf78bfd9
Binary files /dev/null and b/tests/data/meta_size_zero.avif differ
diff --git a/tests/file_layout.cc b/tests/file_layout.cc
index 4daf3322..39c48403 100644
--- a/tests/file_layout.cc
+++ b/tests/file_layout.cc
@@ -44,6 +44,20 @@ TEST_CASE("parse file layout") {
Error err = file.read(reader, heif_get_global_security_limits());
REQUIRE(err.error_code == heif_error_Ok);
+}
+
+
+TEST_CASE("meta box with size 0 (extends to end of file)") {
+ // The 'meta' box uses a box size of 0, which per ISO/IEC 14496-12 clause 4.2
+ // means it extends to the end of the file (legal for the last box). In this
+ // file 'meta' also appears after the media data rather than first. It must
+ // parse successfully (libavif / Chromium read and render this file).
+ auto istr = std::unique_ptr<std::istream>(new std::ifstream(tests_data_directory + "/meta_size_zero.avif", std::ios::binary));
+ auto reader = std::make_shared<StreamReader_istream>(std::move(istr));
- // TODO: read file where 'meta' box is not the first one after 'ftyp'
+ FileLayout file;
+ Error err = file.read(reader, heif_get_global_security_limits());
+
+ REQUIRE(err.error_code == heif_error_Ok);
+ REQUIRE(file.get_meta_box() != nullptr);
}