This is an automated email from the ASF dual-hosted git repository.
pitrou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new ccfcdd24fcb GH-31076: [C++] Reject overflowing STL allocation sizes
(#51477)
ccfcdd24fcb is described below
commit ccfcdd24fcba5c975c476cd246b283a561f21459
Author: khan <[email protected]>
AuthorDate: Thu Oct 1 12:48:48 2026 -0400
GH-31076: [C++] Reject overflowing STL allocation sizes (#51477)
### Rationale for this change
The STL allocator computes `n * sizeof(T)` without checking for overflow.
On a 64-bit platform, requesting `2^61` uint64_t elements wraps the byte count
to zero. Requesting one more element wraps it to eight. Both allocations
incorrectly succeed on upstream commit
`5448aa7a916e73116ccc009454e3c19572dd5aad`, returning less storage than
requested.
### What changes are included in this PR?
Check the element count before multiplication against both the size_t limit
and the int64_t limit used by MemoryPool. Reject oversized requests with the
existing BadAlloc exception, which derives from std::bad_alloc.
Add one regression test covering wraparound to zero and eight bytes. The
test frees any unexpectedly successful allocation before reporting the missing
exception.
### Are these changes tested?
Yes, by additional unit test.
### Are there any user-facing changes?
Just a bugfix.
### Was AI used for this PR?
**PR code and description written by**
- [ ] Human
- [x] AI
**Reviewed before submission by**
- [x] Human
- [x] AI
- [ ] Not reviewed
OpenAI Codex researched the issue and related PRs, wrote the reproducer,
regression test, fix, and this description, ran the listed checks, and reviewed
the diff with another AI agent. Grok was used for preliminary X research. No
external implementation was copied into the patch.
The human author reviewed the complete patch, discussed the overflow checks
and regression test, and takes responsibility for the change.
* GitHub Issue: #31076
Authored-by: Aikhan Jumashukurov
<[email protected]>
Signed-off-by: Antoine Pitrou <[email protected]>
---
cpp/src/arrow/stl_allocator.h | 4 ++++
cpp/src/arrow/stl_test.cc | 14 ++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/cpp/src/arrow/stl_allocator.h b/cpp/src/arrow/stl_allocator.h
index bb52767282e..62585809c78 100644
--- a/cpp/src/arrow/stl_allocator.h
+++ b/cpp/src/arrow/stl_allocator.h
@@ -19,6 +19,7 @@
#include <algorithm>
#include <cstddef>
+#include <limits>
#include <memory>
#include <string>
#include <utility>
@@ -72,6 +73,9 @@ class allocator {
const_pointer address(const_reference r) const noexcept { return
std::addressof(r); }
pointer allocate(size_type n, const void* /*hint*/ = NULLPTR) {
+ if (n > size_max() || n > std::numeric_limits<int64_t>::max() / sizeof(T))
{
+ throw BadAlloc(Status::OutOfMemory("Memory allocation size too large"));
+ }
uint8_t* data;
Status s = pool_->Allocate(n * sizeof(T), &data);
if (!s.ok()) throw BadAlloc(std::move(s));
diff --git a/cpp/src/arrow/stl_test.cc b/cpp/src/arrow/stl_test.cc
index ce5adf0c0e2..39916e1fc00 100644
--- a/cpp/src/arrow/stl_test.cc
+++ b/cpp/src/arrow/stl_test.cc
@@ -558,6 +558,20 @@ TEST(allocator, MemoryTracking) {
ASSERT_EQ(0, pool->bytes_allocated());
}
+TEST(allocator, AllocationSizeOverflow) {
+ allocator<uint64_t> alloc;
+ const size_t first_overflow = std::numeric_limits<size_t>::max() /
sizeof(uint64_t) + 1;
+ for (const size_t n : {first_overflow, first_overflow + 1}) {
+ SCOPED_TRACE(n);
+ EXPECT_THROW(
+ {
+ auto* data = alloc.allocate(n);
+ alloc.deallocate(data, n);
+ },
+ std::bad_alloc);
+ }
+}
+
#if !(defined(ARROW_VALGRIND) || defined(ADDRESS_SANITIZER) ||
defined(ARROW_JEMALLOC))
TEST(allocator, TestOOM) {