diff --git a/include/sonic/dom/dynamicnode.h b/include/sonic/dom/dynamicnode.h index 2678656..0d1af67 100644 --- a/include/sonic/dom/dynamicnode.h +++ b/include/sonic/dom/dynamicnode.h @@ -403,7 +403,7 @@ class DNode : public GenericNode> { size_t cap; map_type* map; - ~MetaNode() { + ~MetaNode() __attribute__((noinline)) { if (map) { map->~map_type(); Allocator::Free(map); diff --git a/tests/allocator_test.cpp b/tests/allocator_test.cpp index 5a44e5f..d3ab08e 100644 --- a/tests/allocator_test.cpp +++ b/tests/allocator_test.cpp @@ -32,6 +32,11 @@ namespace { using namespace sonic_json; +size_t RuntimeHugeAllocationSize() { + volatile size_t size = size_t{1} << 62; + return size; +} + #ifdef SONIC_MEMSTAT #define MEMSTAT_ISEMPTY() EXPECT_TRUE(MemStat::Instance().stat.empty()) #define MEMSTAT_NOTEMPTY() EXPECT_FALSE(MemStat::Instance().stat.empty()) @@ -217,8 +222,7 @@ TEST(Stack, ConstructorOomLeavesConsistentState) { // (absent) buffer. Otherwise Grow()'s guard `top_+cnt >= buf_+cap_` reads // as `1 >= cap_ + 0` and skips the re-allocation entirely, letting a // subsequent Push() dereference a null top_. - constexpr size_t kHuge = (size_t{1} << 62); - sonic_json::internal::Stack s(kHuge); + sonic_json::internal::Stack s(RuntimeHugeAllocationSize()); if (s.Begin() == nullptr) { EXPECT_EQ(0u, s.Capacity()) diff --git a/tests/parser_oom_test.cpp b/tests/parser_oom_test.cpp index 3b455eb..c1b7df1 100644 --- a/tests/parser_oom_test.cpp +++ b/tests/parser_oom_test.cpp @@ -87,15 +87,22 @@ struct AlwaysOomAllocator { static constexpr bool kNeedFree = false; }; +static constexpr size_t kJsonHeadroom = 64; + static std::vector pad_json_bytes(const char* json, size_t len) { - std::vector buf(len + 64, 0); - std::memcpy(buf.data(), json, len); - buf[len] = 'x'; - buf[len + 1] = '"'; - buf[len + 2] = 'x'; + std::vector buf(kJsonHeadroom + len + 64, 0); + uint8_t* data = buf.data() + kJsonHeadroom; + std::memcpy(data, json, len); + data[len] = 'x'; + data[len + 1] = '"'; + data[len + 2] = 'x'; return buf; } +static uint8_t* padded_json_data(std::vector& buf) { + return buf.data() + kJsonHeadroom; +} + TEST(Document, OomDoesNotCrashPushBack) { AlwaysOomAllocator alloc; DNode arr; @@ -244,7 +251,7 @@ TEST(Document, ParseLazyEscapedKeyOomReportsNoMem) { Parser p; const char* json = R"({"\n": 1})"; auto buf = pad_json_bytes(json, std::strlen(json)); - auto res = p.ParseLazy(buf.data(), std::strlen(json), sax); + auto res = p.ParseLazy(padded_json_data(buf), std::strlen(json), sax); EXPECT_EQ(kErrorNoMem, res.Error()); } @@ -304,7 +311,7 @@ TEST(Document, ParseLazyFreesEscapedKeyOnKeyFailure) { Parser p; const char* json = R"({"\n": 1})"; auto buf = pad_json_bytes(json, std::strlen(json)); - p.ParseLazy(buf.data(), std::strlen(json), sax); + p.ParseLazy(padded_json_data(buf), std::strlen(json), sax); ASSERT_TRUE(sax.key_called); EXPECT_EQ(0, SentinelTrackingAllocator::balance); @@ -560,7 +567,7 @@ TEST(ParseLazy, RawRejectionReportsSaxTermination) { Parser p; const char* j = "42"; auto buf = pad_json_bytes(j, 2); - auto r = p.ParseLazy(buf.data(), 2, sax); + auto r = p.ParseLazy(padded_json_data(buf), 2, sax); EXPECT_EQ(r.Error(), kSaxTermination); } @@ -569,7 +576,7 @@ TEST(ParseLazy, StartArrayRejectionReportsSaxTermination) { Parser p; const char* j = "[1,2,3]"; auto buf = pad_json_bytes(j, 7); - auto r = p.ParseLazy(buf.data(), 7, sax); + auto r = p.ParseLazy(padded_json_data(buf), 7, sax); EXPECT_EQ(r.Error(), kSaxTermination); } @@ -578,7 +585,7 @@ TEST(ParseLazy, StartObjectRejectionReportsSaxTermination) { Parser p; const char* j = R"({"k":1})"; auto buf = pad_json_bytes(j, 7); - auto r = p.ParseLazy(buf.data(), 7, sax); + auto r = p.ParseLazy(padded_json_data(buf), 7, sax); EXPECT_EQ(r.Error(), kSaxTermination); } @@ -599,7 +606,7 @@ TEST(ParseLazy, AcceptAllStillCompletesCleanly) { Parser p; const char* j = R"({"a":1,"b":[2,3]})"; auto buf = pad_json_bytes(j, std::strlen(j)); - auto r = p.ParseLazy(buf.data(), std::strlen(j), sax); + auto r = p.ParseLazy(padded_json_data(buf), std::strlen(j), sax); EXPECT_EQ(r.Error(), kErrorNone); }