diff --git a/CHANGELOG.md b/CHANGELOG.md index 498a8853..9688cb99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ ArduinoJson: change log ======================= +HEAD +---- + +* Fix assertion `poolIndex < count_` after `JsonDocument::clear()` (issue #2034) + v7.0.1 (2024-01-10) ------ diff --git a/extras/tests/JsonDocument/CMakeLists.txt b/extras/tests/JsonDocument/CMakeLists.txt index d1ac1aa6..e6b6f1db 100644 --- a/extras/tests/JsonDocument/CMakeLists.txt +++ b/extras/tests/JsonDocument/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(JsonDocumentTests add.cpp assignment.cpp cast.cpp + clear.cpp compare.cpp constructor.cpp containsKey.cpp diff --git a/extras/tests/JsonDocument/clear.cpp b/extras/tests/JsonDocument/clear.cpp new file mode 100644 index 00000000..8d3f2276 --- /dev/null +++ b/extras/tests/JsonDocument/clear.cpp @@ -0,0 +1,47 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2024, Benoit BLANCHON +// MIT License + +#include +#include + +#include // malloc, free +#include + +#include "Allocators.hpp" + +TEST_CASE("JsonDocument::clear()") { + SpyingAllocator spy; + JsonDocument doc(&spy); + + SECTION("null") { + doc.clear(); + + REQUIRE(doc.isNull()); + REQUIRE(spy.log() == AllocatorLog{}); + } + + SECTION("releases resources") { + doc[std::string("hello")] = std::string("world"); + spy.clearLog(); + + doc.clear(); + + REQUIRE(doc.isNull()); + REQUIRE(spy.log() == AllocatorLog{ + Deallocate(sizeofPool()), + Deallocate(sizeofString("hello")), + Deallocate(sizeofString("world")), + }); + } + + SECTION("clear free list") { // issue #2034 + JsonObject obj = doc.to(); + obj["a"] = 1; + obj.clear(); // puts the slot in the free list + + doc.clear(); + + doc["b"] = 2; // will it pick from the free list? + } +} diff --git a/src/ArduinoJson/Memory/VariantPoolList.hpp b/src/ArduinoJson/Memory/VariantPoolList.hpp index 49a05d3b..8ee5cef6 100644 --- a/src/ArduinoJson/Memory/VariantPoolList.hpp +++ b/src/ArduinoJson/Memory/VariantPoolList.hpp @@ -103,6 +103,7 @@ class VariantPoolList { for (PoolCount i = 0; i < count_; i++) pools_[i].destroy(allocator); count_ = 0; + freeList_ = NULL_SLOT; if (pools_ != preallocatedPools_) { allocator->deallocate(pools_); pools_ = preallocatedPools_;