Skip to content

Commit

Permalink
Explicit iterative destruction of JSON containers (objects and arrays…
Browse files Browse the repository at this point in the history
…) instead of implicit recursive destruction in order to avoid stack overflows for deeply nested hierarchies
  • Loading branch information
jonathan-meier committed Jan 14, 2019
1 parent e5753b1 commit ed953be
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 20 deletions.
75 changes: 65 additions & 10 deletions include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -997,18 +997,73 @@ class basic_json
switch (t)
{
case value_t::object:
{
AllocatorType<object_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
break;
}

case value_t::array:
{
AllocatorType<array_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
if ((t == value_t::object && !this->object->empty()) || (t == value_t::array && !this->array->empty()))
{
std::vector<std::pair<json_value*, value_t>> stack;
stack.push_back(std::make_pair(this, t));
while (!stack.empty())
{
json_value* value;
value_t type;
std::tie(value, type) = stack.back();
if (type == value_t::object)
{
while (!value->object->empty())
{
basic_json& inner_value = value->object->begin()->second;
value_t inner_type = inner_value.type();
if ((inner_type == value_t::object || inner_type == value_t::array) && !inner_value.empty())
{
stack.push_back(std::make_pair(&inner_value.m_value, inner_type));
break;
}
else
{
value->object->erase(value->object->begin());
}
}
if (value->object->empty())
{
stack.pop_back();
}
}
else
{
while (!value->array->empty())
{
basic_json& inner_value = value->array->back();
value_t inner_type = inner_value.type();
if ((inner_type == value_t::object || inner_type == value_t::array) && !inner_value.empty())
{
stack.push_back(std::make_pair(&inner_value.m_value, inner_type));
break;
}
else
{
value->array->pop_back();
}
}
if (value->array->empty())
{
stack.pop_back();
}
}
}
}
if (t == value_t::object)
{
AllocatorType<object_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
}
else
{
AllocatorType<array_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
}
break;
}

Expand Down
75 changes: 65 additions & 10 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13465,18 +13465,73 @@ class basic_json
switch (t)
{
case value_t::object:
{
AllocatorType<object_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
break;
}

case value_t::array:
{
AllocatorType<array_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
if ((t == value_t::object && !this->object->empty()) || (t == value_t::array && !this->array->empty()))
{
std::vector<std::pair<json_value*, value_t>> stack;
stack.push_back(std::make_pair(this, t));
while (!stack.empty())
{
json_value* value;
value_t type;
std::tie(value, type) = stack.back();
if (type == value_t::object)
{
while (!value->object->empty())
{
basic_json& inner_value = value->object->begin()->second;
value_t inner_type = inner_value.type();
if ((inner_type == value_t::object || inner_type == value_t::array) && !inner_value.empty())
{
stack.push_back(std::make_pair(&inner_value.m_value, inner_type));
break;
}
else
{
value->object->erase(value->object->begin());
}
}
if (value->object->empty())
{
stack.pop_back();
}
}
else
{
while (!value->array->empty())
{
basic_json& inner_value = value->array->back();
value_t inner_type = inner_value.type();
if ((inner_type == value_t::object || inner_type == value_t::array) && !inner_value.empty())
{
stack.push_back(std::make_pair(&inner_value.m_value, inner_type));
break;
}
else
{
value->array->pop_back();
}
}
if (value->array->empty())
{
stack.pop_back();
}
}
}
}
if (t == value_t::object)
{
AllocatorType<object_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
}
else
{
AllocatorType<array_t> alloc;
std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
}
break;
}

Expand Down

0 comments on commit ed953be

Please sign in to comment.