Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions include/simdjson/generic/dom_parser_implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,21 @@ inline simdjson_warn_unused error_code dom_parser_implementation::set_capacity(s
}

inline simdjson_warn_unused error_code dom_parser_implementation::set_max_depth(size_t max_depth) noexcept {
// Keep depth-stack allocations safely below implementation-specific array-new limits.
static constexpr size_t max_depth_allocation_bytes = size_t(1) << 28; // 256 MiB
if (simdjson_unlikely(
max_depth > max_depth_allocation_bytes / sizeof(open_container) ||
max_depth > max_depth_allocation_bytes / sizeof(bool))) {
return CAPACITY;
}

std::unique_ptr<open_container[]> new_open_containers(new (std::nothrow) open_container[max_depth]);
std::unique_ptr<bool[]> new_is_array(new (std::nothrow) bool[max_depth]);
if (!new_is_array || !new_open_containers) { return MEMALLOC; }

// Stage 2 stacks
open_containers.reset(new (std::nothrow) open_container[max_depth]);
is_array.reset(new (std::nothrow) bool[max_depth]);
if (!is_array || !open_containers) { _max_depth = 0; return MEMALLOC; }
open_containers.swap(new_open_containers);
is_array.swap(new_is_array);

_max_depth = max_depth;
return SUCCESS;
Expand Down
21 changes: 17 additions & 4 deletions include/simdjson/generic/ondemand/parser-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,32 @@ simdjson_warn_unused simdjson_inline error_code parser::allocate(size_t new_capa
if (new_capacity > max_capacity()) { return CAPACITY; }
if (string_buf && new_capacity == capacity() && new_max_depth == max_depth()) { return SUCCESS; }

#if SIMDJSON_DEVELOPMENT_CHECKS
static constexpr size_t max_depth_allocation_bytes = size_t(1) << 28; // 256 MiB
if (simdjson_unlikely(new_max_depth > max_depth_allocation_bytes / sizeof(token_position))) {
return CAPACITY;
}
#endif

// string_capacity copied from document::allocate
_capacity = 0;
size_t string_capacity = SIMDJSON_ROUNDUP_N(5 * new_capacity / 3 + SIMDJSON_PADDING, 64);
string_buf.reset(new (std::nothrow) uint8_t[string_capacity]);
std::unique_ptr<uint8_t[]> new_string_buf(new (std::nothrow) uint8_t[string_capacity]);
if (!new_string_buf) { return MEMALLOC; }
#if SIMDJSON_DEVELOPMENT_CHECKS
start_positions.reset(new (std::nothrow) token_position[new_max_depth]);
std::unique_ptr<token_position[]> new_start_positions(new (std::nothrow) token_position[new_max_depth]);
if (!new_start_positions) { return MEMALLOC; }
#endif
if (implementation) {
SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
SIMDJSON_TRY( implementation->set_max_depth(new_max_depth) );
SIMDJSON_TRY( implementation->set_capacity(new_capacity) );
} else {
SIMDJSON_TRY( simdjson::get_active_implementation()->create_dom_parser_implementation(new_capacity, new_max_depth, implementation) );
}

string_buf.swap(new_string_buf);
#if SIMDJSON_DEVELOPMENT_CHECKS
start_positions.swap(new_start_positions);
#endif
_capacity = new_capacity;
_max_depth = new_max_depth;
return SUCCESS;
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ link_libraries(simdjson)
add_cpp_test(unicode_tests LABELS dom acceptance per_implementation)
add_cpp_test(minify_tests LABELS other acceptance per_implementation)
add_cpp_test(padded_string_tests LABELS other acceptance )
add_cpp_test(parser_max_depth_tests LABELS other acceptance )
add_cpp_test(memory_map_tests LABELS other acceptance )
add_cpp_test(prettify_tests LABELS other acceptance per_implementation)
add_cpp_test(fractured_json_tests LABELS other acceptance per_implementation)
Expand Down
39 changes: 39 additions & 0 deletions tests/parser_max_depth_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "simdjson.h"
#include "test_macros.h"

#include <cstdlib>
#include <limits>

static constexpr size_t max_size_t_depth = (std::numeric_limits<size_t>::max)();
static constexpr size_t invalid_max_depth_values[] = {
max_size_t_depth,
max_size_t_depth / 2,
max_size_t_depth / 8,
max_size_t_depth / 16
};

static bool dom_parser_depth_overflow_is_capacity() {
TEST_START();
simdjson::dom::parser parser(simdjson::SIMDJSON_MAXSIZE_BYTES);
for (size_t depth : invalid_max_depth_values) {
ASSERT_ERROR(parser.allocate(simdjson::dom::MINIMAL_DOCUMENT_CAPACITY, depth), simdjson::CAPACITY);
}
TEST_SUCCEED();
}

static bool ondemand_parser_depth_overflow_is_capacity() {
TEST_START();
simdjson::ondemand::parser parser(simdjson::SIMDJSON_MAXSIZE_BYTES);
for (size_t depth : invalid_max_depth_values) {
ASSERT_ERROR(parser.allocate(simdjson::dom::MINIMAL_DOCUMENT_CAPACITY, depth), simdjson::CAPACITY);
}
TEST_SUCCEED();
}

int main() {
RUN_TEST(dom_parser_depth_overflow_is_capacity());
RUN_TEST(ondemand_parser_depth_overflow_is_capacity());

std::cout << "All tests passed!" << std::endl;
return EXIT_SUCCESS;
}
Loading