Commit b453ecc0 for libheif
commit b453ecc023a069ec2692b6e428123fd89967cee8
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Thu Jul 2 12:19:14 2026 +0200
Fix bisect_filesize integer overflow when probing file size (#1857)
StreamReader_CApi::bisect_filesize() computed its probe position as
(mini + maxi) / 2, which overflows uint64_t when 'maxi' is large. This
path is now reachable because file_layout.cc resolves a 'meta' box of
size 0 by calling request_range(start, UINT64_MAX) to obtain the file
size, and the version-1 reader fallback bisects the size.
Two problems are fixed:
- Use the overflow-safe midpoint mini + (maxi - mini) / 2.
- wait_for_file_size() takes a signed int64_t. Probing a position beyond
INT64_MAX wraps to a negative value, which a reader compares as "below
the file size" and reports as size_reached, driving the search to a
bogus multi-exabyte result. Clamp the probe range to INT64_MAX (no file
handled through this API can be larger) so both the initial
wait_for_file_size() call and the bisection stay in the valid range.
Behaviour is unchanged for all existing callers, which pass an end
position well below INT64_MAX.
diff --git a/libheif/bitstream.h b/libheif/bitstream.h
index c04de251..da6acf1e 100644
--- a/libheif/bitstream.h
+++ b/libheif/bitstream.h
@@ -206,13 +206,20 @@ public:
}
}
else {
- auto result = m_func_table->wait_for_file_size(end_pos, m_userdata);
+ // wait_for_file_size() takes a signed int64_t, so we cannot probe a position
+ // beyond INT64_MAX: it would wrap to a negative value and the reader would
+ // misreport the size. No file accessed through this API can be that large,
+ // so clamp the search range to INT64_MAX. (Callers may pass UINT64_MAX to
+ // ask for the total file size.)
+ uint64_t hi = std::min<uint64_t>(end_pos, std::numeric_limits<int64_t>::max());
+
+ auto result = m_func_table->wait_for_file_size(static_cast<int64_t>(hi), m_userdata);
if (result == heif_reader_grow_status_size_reached) {
- return end_pos;
+ return hi;
}
else {
uint64_t pos = m_func_table->get_position(m_userdata);
- return bisect_filesize(pos,end_pos);
+ return bisect_filesize(pos, hi);
}
}
}
@@ -225,8 +232,10 @@ public:
return mini;
}
- uint64_t pos = (mini + maxi) / 2;
- auto result = m_func_table->wait_for_file_size(pos, m_userdata);
+ // Overflow-safe midpoint. 'maxi' is bounded by INT64_MAX (see request_range),
+ // but computing (mini + maxi) directly could still overflow uint64_t.
+ uint64_t pos = mini + (maxi - mini) / 2;
+ auto result = m_func_table->wait_for_file_size(static_cast<int64_t>(pos), m_userdata);
if (result == heif_reader_grow_status_size_reached) {
return bisect_filesize(pos, maxi);
}