From ec6d63291c7e7bec0c0606bfd652636280dd169a Mon Sep 17 00:00:00 2001 From: Old-Ding <35417409+Old-Ding@users.noreply.github.com> Date: Sat, 11 Jul 2026 16:05:42 +0800 Subject: [PATCH] Fix hash map capacity overflow Reject capacities that wrap while rounding or overflow the bucket array allocation. Use the bucket element type for the allocation size. Signed-off-by: Old-Ding <35417409+Old-Ding@users.noreply.github.com> --- src/hash_map.c | 8 ++++++-- test/test_hash_map.cpp | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/hash_map.c b/src/hash_map.c index 28748d6b..c2c2376b 100644 --- a/src/hash_map.c +++ b/src/hash_map.c @@ -19,6 +19,7 @@ extern "C" #include #include +#include #include "rcutils/allocator.h" #include "rcutils/error_handling.h" @@ -86,7 +87,10 @@ static rcutils_ret_t hash_map_allocate_new_map( rcutils_array_list_t ** map, size_t capacity, const rcutils_allocator_t * allocator) { - *map = allocator->allocate(capacity * sizeof(rcutils_hash_map_impl_t), allocator->state); + if (0 == capacity || capacity > SIZE_MAX / sizeof(rcutils_array_list_t)) { + return RCUTILS_RET_BAD_ALLOC; + } + *map = allocator->allocate(capacity * sizeof(rcutils_array_list_t), allocator->state); if (NULL == *map) { return RCUTILS_RET_BAD_ALLOC; } @@ -240,7 +244,7 @@ static size_t next_power_of_two(size_t v) v |= v >> shf; } v++; - return v > 1 ? v : 1; + return v; } rcutils_ret_t diff --git a/test/test_hash_map.cpp b/test/test_hash_map.cpp index ab8ccbcf..bb3193ba 100644 --- a/test/test_hash_map.cpp +++ b/test/test_hash_map.cpp @@ -107,6 +107,22 @@ TEST_F(HashMapBaseTest, init_map_initial_capacity_not_power_of_two) { EXPECT_EQ(RCUTILS_RET_OK, ret) << rcutils_get_error_string().str; } +TEST_F(HashMapBaseTest, init_map_initial_capacity_overflow_fails) { + rcutils_ret_t ret = rcutils_hash_map_init( + &map, SIZE_MAX, sizeof(uint32_t), sizeof(uint32_t), + test_hash_map_uint32_hash_func, test_uint32_cmp, &allocator); + EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, ret) << rcutils_get_error_string().str; + EXPECT_EQ(nullptr, map.impl); +} + +TEST_F(HashMapBaseTest, init_map_allocation_size_overflow_fails) { + rcutils_ret_t ret = rcutils_hash_map_init( + &map, (SIZE_MAX >> 1) + 1, sizeof(uint32_t), sizeof(uint32_t), + test_hash_map_uint32_hash_func, test_uint32_cmp, &allocator); + EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, ret) << rcutils_get_error_string().str; + EXPECT_EQ(nullptr, map.impl); +} + TEST_F(HashMapBaseTest, init_map_key_size_zero_fails) { rcutils_ret_t ret = rcutils_hash_map_init( &map, 2, 0, sizeof(uint32_t),