VariantPoolList: handle SlotId overflow

This commit is contained in:
Benoit Blanchon
2023-07-20 19:04:40 +02:00
parent 8be0d57d24
commit f427706e06
3 changed files with 41 additions and 1 deletions

View File

@ -10,6 +10,11 @@ add_executable(ResourceManagerTests
StringBuilder.cpp StringBuilder.cpp
) )
add_compile_definitions(ResourceManagerTests
ARDUINOJSON_SLOT_ID_SIZE=1 # require less RAM for overflow tests
ARDUINOJSON_POOL_CAPACITY=16
)
add_test(ResourceManager ResourceManagerTests) add_test(ResourceManager ResourceManagerTests)
set_tests_properties(ResourceManager set_tests_properties(ResourceManager

View File

@ -66,4 +66,30 @@ TEST_CASE("ResourceManager::allocSlot()") {
REQUIRE(variant.id() == NULL_SLOT); REQUIRE(variant.id() == NULL_SLOT);
REQUIRE(static_cast<VariantSlot*>(variant) == nullptr); REQUIRE(static_cast<VariantSlot*>(variant) == nullptr);
} }
SECTION("Try overflow pool counter") {
ResourceManager resources;
// this test assumes SlotId is 8-bit; otherwise it consumes a lot of memory
// tyhe GitHub Workflow gets killed
REQUIRE(NULL_SLOT == 255);
// fill all the pools
for (SlotId i = 0; i < NULL_SLOT; i++) {
auto slot = resources.allocSlot();
REQUIRE(slot.id() == i); // or != NULL_SLOT
REQUIRE(static_cast<VariantSlot*>(slot) != nullptr);
}
REQUIRE(resources.overflowed() == false);
// now all allocations should fail
for (int i = 0; i < 10; i++) {
auto slot = resources.allocSlot();
REQUIRE(slot.id() == NULL_SLOT);
REQUIRE(static_cast<VariantSlot*>(slot) == nullptr);
}
REQUIRE(resources.overflowed() == true);
}
} }

View File

@ -108,11 +108,16 @@ class VariantPoolList {
if (count_ == capacity_ && !increaseCapacity(allocator)) if (count_ == capacity_ && !increaseCapacity(allocator))
return nullptr; return nullptr;
auto pool = &pools_[count_++]; auto pool = &pools_[count_++];
pool->create(ARDUINOJSON_POOL_CAPACITY, allocator); SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY;
if (count_ == maxPools) // last pool is smaller because of NULL_SLOT
poolCapacity--;
pool->create(poolCapacity, allocator);
return pool; return pool;
} }
bool increaseCapacity(Allocator* allocator) { bool increaseCapacity(Allocator* allocator) {
if (count_ == maxPools)
return false;
void* newPools; void* newPools;
PoolCount newCapacity; PoolCount newCapacity;
if (pools_) { if (pools_) {
@ -134,6 +139,10 @@ class VariantPoolList {
PoolCount count_ = 0; PoolCount count_ = 0;
PoolCount capacity_ = 0; PoolCount capacity_ = 0;
SlotId freeList_ = NULL_SLOT; SlotId freeList_ = NULL_SLOT;
public:
static const PoolCount maxPools =
PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1);
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE