diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc index 531458d1addca..ac311435f4d1b 100644 --- a/src/google/protobuf/arena_unittest.cc +++ b/src/google/protobuf/arena_unittest.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include // IWYU pragma: keep for operator new #include @@ -72,6 +73,7 @@ using proto2_unittest::TestRepeatedString; using ::testing::AnyOf; using ::testing::ElementsAre; using ::testing::ElementsAreArray; +using ::testing::Gt; using ::testing::HasSubstr; using ::testing::Optional; using ::testing::Pointee; @@ -1786,6 +1788,34 @@ TEST(ArenaTest, StartingBlockSize) { EXPECT_EQ(custom_arena.SpaceAllocated(), options.start_block_size); } +TEST(ArenaTest, VeryLargeAllocIn32BitMode) { + if (sizeof(size_t) != 4) { + GTEST_SKIP() << "Only care about 32-bit mode."; + } + + static absl::optional large_allocation_size; + + // Make sure we don't have bugs allocating buffers greater that ptrdiff_t max. + // It will likely fail, but it should fail in the allocator. + + ArenaOptions options; + options.block_alloc = [](size_t n) { + if (n > size_t{std::numeric_limits::max()}) { + large_allocation_size = n; + // Just fake it. Doesn't matter. + n = 1000000; + } + return ::operator new(n); + }; + options.block_dealloc = [](void* ptr, size_t) { ::operator delete(ptr); }; + + Arena arena(options); + void* ptr = arena.AllocateAligned(size_t{1} << 31); + EXPECT_NE(ptr, nullptr); + EXPECT_THAT(large_allocation_size, + Optional(Gt(size_t{std::numeric_limits::max()}))); +} + TEST(ArenaTest, BlockSizeDoubling) { Arena arena; EXPECT_EQ(0, arena.SpaceUsed()); diff --git a/src/google/protobuf/serial_arena.h b/src/google/protobuf/serial_arena.h index 21bab3f52b875..b529a74bed377 100644 --- a/src/google/protobuf/serial_arena.h +++ b/src/google/protobuf/serial_arena.h @@ -202,7 +202,7 @@ class PROTOBUF_EXPORT SerialArena { ABSL_DCHECK(internal::ArenaAlignDefault::IsAligned(n)); ABSL_DCHECK_GE(limit_, ptr()); char* ret = ptr(); - if (ABSL_PREDICT_FALSE(limit_ - ret < static_cast(n))) { + if (ABSL_PREDICT_FALSE(static_cast(limit_ - ret) < n)) { return false; } internal::UnpoisonMemoryRegion(ret, n);