Commit 38d73faa for libheif
commit 38d73faaeff4d77366af8b67c3781ec44329d67a
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Thu May 28 14:58:18 2026 +0200
add MemoryHandle::alloc() overload with int overflow checking
diff --git a/libheif/codecs/uncompressed/unc_boxes.cc b/libheif/codecs/uncompressed/unc_boxes.cc
index 4e938104..714a9348 100644
--- a/libheif/codecs/uncompressed/unc_boxes.cc
+++ b/libheif/codecs/uncompressed/unc_boxes.cc
@@ -1345,14 +1345,7 @@ Error Box_snuc::parse(BitstreamRange& range, const heif_security_limits* limits)
"snuc image dimensions exceed security limit."};
}
- // Prevent size_t overflow when computing alloc size (matters on 32-bit systems)
- if (std::numeric_limits<size_t>::max() / num_pixels < 2 * sizeof(float)) {
- return {heif_error_Invalid_input,
- heif_suberror_Security_limit_exceeded,
- "snuc image memory size exceeds max integer size."};
- }
-
- Error err = m_memory_handle.alloc(2 * sizeof(float) * num_pixels, limits, "snuc box");
+ Error err = m_memory_handle.alloc(num_pixels, 2 * sizeof(float), limits, "snuc box");
if (err) {
return err;
}
diff --git a/libheif/region.cc b/libheif/region.cc
index b318c3d7..8db2dbce 100644
--- a/libheif/region.cc
+++ b/libheif/region.cc
@@ -358,7 +358,7 @@ Error RegionGeometry_Polygon::parse(const std::vector<uint8_t>& data,
};
}
- if (auto err = m_memory_handle.alloc(numPoints * sizeof(Point), limits, "region polygon")) {
+ if (auto err = m_memory_handle.alloc(numPoints, sizeof(Point), limits, "region polygon")) {
return err;
}
diff --git a/libheif/security_limits.cc b/libheif/security_limits.cc
index 1a85b3ed..4809306f 100644
--- a/libheif/security_limits.cc
+++ b/libheif/security_limits.cc
@@ -196,6 +196,27 @@ size_t TotalMemoryTracker::get_max_total_memory_used() const
}
+Error MemoryHandle::alloc(size_t count, size_t element_size,
+ const heif_security_limits* limits_context,
+ const char* reason_description)
+{
+ if (element_size != 0 && count > SIZE_MAX / element_size) {
+ std::stringstream sstr;
+ if (reason_description) {
+ sstr << "Allocation size overflow computing " << count << " * " << element_size
+ << " for " << reason_description;
+ }
+ else {
+ sstr << "Allocation size overflow computing " << count << " * " << element_size;
+ }
+ return {heif_error_Memory_allocation_error,
+ heif_suberror_Security_limit_exceeded,
+ sstr.str()};
+ }
+ return alloc(count * element_size, limits_context, reason_description);
+}
+
+
Error MemoryHandle::alloc(size_t memory_amount, const heif_security_limits* limits_context,
const char* reason_description)
{
diff --git a/libheif/security_limits.h b/libheif/security_limits.h
index a8abb4d2..2db08e83 100644
--- a/libheif/security_limits.h
+++ b/libheif/security_limits.h
@@ -86,6 +86,12 @@ public:
Error alloc(size_t memory_amount, const heif_security_limits* limits_context, const char* reason_description);
+ // calloc-style overload: checks `count * element_size` for size_t overflow before allocating.
+ // Use this when allocating an array whose total size is count*element_size, to avoid silent
+ // truncation on 32-bit builds when count is near UINT32_MAX.
+ Error alloc(size_t count, size_t element_size,
+ const heif_security_limits* limits_context, const char* reason_description);
+
void free();
void free(size_t memory_amount);
diff --git a/libheif/sequences/seq_boxes.cc b/libheif/sequences/seq_boxes.cc
index 54eaca5a..69900856 100644
--- a/libheif/sequences/seq_boxes.cc
+++ b/libheif/sequences/seq_boxes.cc
@@ -561,7 +561,7 @@ Error Box_stts::parse(BitstreamRange& range, const heif_security_limits* limits)
};
}
- if (auto err = m_memory_handle.alloc(entry_count * sizeof(TimeToSample),
+ if (auto err = m_memory_handle.alloc(entry_count, sizeof(TimeToSample),
limits, "the 'stts' table")) {
return err;
}
@@ -693,7 +693,7 @@ Error Box_ctts::parse(BitstreamRange& range, const heif_security_limits* limits)
};
}
- if (auto err = m_memory_handle.alloc(entry_count * sizeof(OffsetToSample),
+ if (auto err = m_memory_handle.alloc(entry_count, sizeof(OffsetToSample),
limits, "the 'ctts' table")) {
return err;
}
@@ -871,7 +871,7 @@ Error Box_stsc::parse(BitstreamRange& range, const heif_security_limits* limits)
}
- if (auto err = m_memory_handle.alloc(entry_count * sizeof(SampleToChunk),
+ if (auto err = m_memory_handle.alloc(entry_count, sizeof(SampleToChunk),
limits, "the 'stsc' table")) {
return err;
}
@@ -1086,8 +1086,8 @@ Error Box_stsz::parse(BitstreamRange& range, const heif_security_limits* limits)
if (m_fixed_sample_size == 0) {
// check required memory
- uint64_t mem_size = m_sample_count * sizeof(uint32_t);
- if (auto err = m_memory_handle.alloc(mem_size, limits, "the 'stsz' table")) {
+ if (auto err = m_memory_handle.alloc(m_sample_count, sizeof(uint32_t),
+ limits, "the 'stsz' table")) {
return err;
}
@@ -1194,8 +1194,8 @@ Error Box_stss::parse(BitstreamRange& range, const heif_security_limits* limits)
// check required memory
- uint64_t mem_size = sample_count * sizeof(uint32_t);
- if (auto err = m_memory_handle.alloc(mem_size, limits, "the 'stss' table")) {
+ if (auto err = m_memory_handle.alloc(sample_count, sizeof(uint32_t),
+ limits, "the 'stss' table")) {
return err;
}
@@ -1611,7 +1611,7 @@ Error Box_sbgp::parse(BitstreamRange& range, const heif_security_limits* limits)
}
uint32_t count = range.read32();
- if (auto err = m_memory_handle.alloc(count * sizeof(Entry),
+ if (auto err = m_memory_handle.alloc(count, sizeof(Entry),
limits, "the 'sample to group' table")) {
return err;
}
@@ -1750,7 +1750,7 @@ Error Box_sgpd::parse(BitstreamRange& range, const heif_security_limits* limits)
}
- if (auto err = m_memory_handle.alloc(static_cast<uint64_t>(entry_count) * sizeof(Entry),
+ if (auto err = m_memory_handle.alloc(entry_count, sizeof(Entry),
limits, "the 'sgpd' table")) {
return err;
}
@@ -2131,10 +2131,8 @@ Error Box_saio::parse(BitstreamRange& range, const heif_security_limits* limits)
};
}
- // check required memory
- uint64_t mem_size = num_chunks * sizeof(uint64_t);
-
- if (auto err = m_memory_handle.alloc(mem_size, limits, "the 'saio' table")) {
+ if (auto err = m_memory_handle.alloc(num_chunks, sizeof(uint64_t),
+ limits, "the 'saio' table")) {
return err;
}