diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index e0b5dcc71..0090f5a30 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -125,8 +125,7 @@ class serializer o->write_characters("{\n", 2); // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - reserve_indent(new_indent); + const auto new_indent = reserve_indent(current_indent, indent_step); // first n-1 elements auto i = val.m_data.m_value.object->cbegin(); @@ -195,8 +194,7 @@ class serializer o->write_characters("[\n", 2); // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - reserve_indent(new_indent); + const auto new_indent = reserve_indent(current_indent, indent_step); // first n-1 elements for (auto i = val.m_data.m_value.array->cbegin(); @@ -253,8 +251,7 @@ class serializer o->write_characters("{\n", 2); // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - reserve_indent(new_indent); + const auto new_indent = reserve_indent(current_indent, indent_step); o->write_characters(indent_string.c_str(), new_indent); @@ -365,22 +362,30 @@ class serializer } /*! - @brief grow the indentation string so it can hold at least @a new_indent characters + @brief compute the next indentation level and grow the indentation string - The indentation string is grown by doubling its size, but at least to - @a new_indent characters, so that it can be used as a source for writing - @a new_indent indentation characters. The newly added characters use the - configured @ref indent_char. + Computes the new indentation level @a current_indent + @a indent_step and + grows the indentation string (by doubling its size, but at least to the new + level) so that it can be used as a source for writing that many indentation + characters. The newly added characters use the configured @ref indent_char. - @param[in] new_indent the required number of indentation characters + @param[in] current_indent the current indentation level + @param[in] indent_step the number of characters to indent per level + + @return the new indentation level @a current_indent + @a indent_step */ - void reserve_indent(const std::size_t new_indent) + unsigned int reserve_indent(const unsigned int current_indent, const unsigned int indent_step) { + const unsigned int new_indent = current_indent + indent_step; + // a very large indent_step can wrap the unsigned accumulation on deep + // nesting, which would silently truncate the indentation + JSON_ASSERT(new_indent >= current_indent); if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) { - indent_string.resize((std::max)(indent_string.size() * 2, new_indent), indent_char); + indent_string.resize((std::max)(indent_string.size() * 2, static_cast(new_indent)), indent_char); } JSON_ASSERT(indent_string.size() >= new_indent); + return new_indent; } JSON_PRIVATE_UNLESS_TESTED: diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 7408238c2..a5fc13f5c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -19299,8 +19299,7 @@ class serializer o->write_characters("{\n", 2); // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - reserve_indent(new_indent); + const auto new_indent = reserve_indent(current_indent, indent_step); // first n-1 elements auto i = val.m_data.m_value.object->cbegin(); @@ -19369,8 +19368,7 @@ class serializer o->write_characters("[\n", 2); // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - reserve_indent(new_indent); + const auto new_indent = reserve_indent(current_indent, indent_step); // first n-1 elements for (auto i = val.m_data.m_value.array->cbegin(); @@ -19427,8 +19425,7 @@ class serializer o->write_characters("{\n", 2); // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - reserve_indent(new_indent); + const auto new_indent = reserve_indent(current_indent, indent_step); o->write_characters(indent_string.c_str(), new_indent); @@ -19539,22 +19536,30 @@ class serializer } /*! - @brief grow the indentation string so it can hold at least @a new_indent characters + @brief compute the next indentation level and grow the indentation string - The indentation string is grown by doubling its size, but at least to - @a new_indent characters, so that it can be used as a source for writing - @a new_indent indentation characters. The newly added characters use the - configured @ref indent_char. + Computes the new indentation level @a current_indent + @a indent_step and + grows the indentation string (by doubling its size, but at least to the new + level) so that it can be used as a source for writing that many indentation + characters. The newly added characters use the configured @ref indent_char. - @param[in] new_indent the required number of indentation characters + @param[in] current_indent the current indentation level + @param[in] indent_step the number of characters to indent per level + + @return the new indentation level @a current_indent + @a indent_step */ - void reserve_indent(const std::size_t new_indent) + unsigned int reserve_indent(const unsigned int current_indent, const unsigned int indent_step) { + const unsigned int new_indent = current_indent + indent_step; + // a very large indent_step can wrap the unsigned accumulation on deep + // nesting, which would silently truncate the indentation + JSON_ASSERT(new_indent >= current_indent); if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) { - indent_string.resize((std::max)(indent_string.size() * 2, new_indent), indent_char); + indent_string.resize((std::max)(indent_string.size() * 2, static_cast(new_indent)), indent_char); } JSON_ASSERT(indent_string.size() >= new_indent); + return new_indent; } JSON_PRIVATE_UNLESS_TESTED: