diff options
-rw-r--r-- | src/pugixpath.cpp | 36 | ||||
-rw-r--r-- | tests/test_xpath_parse.cpp | 12 |
2 files changed, 28 insertions, 20 deletions
diff --git a/src/pugixpath.cpp b/src/pugixpath.cpp index 1e20d8c..d67eac6 100644 --- a/src/pugixpath.cpp +++ b/src/pugixpath.cpp @@ -497,35 +497,30 @@ namespace #endif } - double convert_string_to_number(const char_t* begin, const char_t* end) + bool convert_string_to_number(const char_t* begin, const char_t* end, double* out_result) { char_t buffer[32]; size_t length = static_cast<size_t>(end - begin); + char_t* scratch = buffer; - if (length < sizeof(buffer) / sizeof(buffer[0])) - { - // optimized on-stack conversion - memcpy(buffer, begin, length * sizeof(char_t)); - buffer[length] = 0; - - return convert_string_to_number(buffer); - } - else + if (length >= sizeof(buffer) / sizeof(buffer[0])) { // need to make dummy on-heap copy - char_t* copy = static_cast<char_t*>(get_memory_allocation_function()((length + 1) * sizeof(char_t))); - if (!copy) return gen_nan(); // $$ out of memory + scratch = static_cast<char_t*>(get_memory_allocation_function()((length + 1) * sizeof(char_t))); + if (!scratch) return false; + } - memcpy(copy, begin, length * sizeof(char_t)); - copy[length] = 0; + // copy string to zero-terminated buffer and perform conversion + memcpy(scratch, begin, length * sizeof(char_t)); + scratch[length] = 0; - double result = convert_string_to_number(copy); + *out_result = convert_string_to_number(scratch); - get_memory_deallocation_function()(copy); + // free dummy buffer + if (scratch != buffer) get_memory_deallocation_function()(scratch); - return result; - } + return true; } double round_nearest(double value) @@ -2899,7 +2894,10 @@ namespace pugi case lex_number: { - double value = convert_string_to_number(_lexer.contents().begin, _lexer.contents().end); + double value = 0; + + if (!convert_string_to_number(_lexer.contents().begin, _lexer.contents().end, &value)) + throw_error("Out of memory"); xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value); _lexer.next(); diff --git a/tests/test_xpath_parse.cpp b/tests/test_xpath_parse.cpp index b8e46d9..f17357b 100644 --- a/tests/test_xpath_parse.cpp +++ b/tests/test_xpath_parse.cpp @@ -269,15 +269,25 @@ TEST_XML(xpath_parse_absolute, "<div><s/></div>") CHECK_XPATH_NODESET(doc, STR("/*[/]")) % 2; } -TEST(xpath_parse_out_of_memory) +TEST(xpath_parse_out_of_memory_first_page) { test_runner::_memory_fail_threshold = 1; CHECK_XPATH_FAIL(STR("1")); +} +TEST(xpath_parse_out_of_memory_second_page_node) +{ test_runner::_memory_fail_threshold = 8192; CHECK_XPATH_FAIL(STR("1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1")); } +TEST(xpath_parse_out_of_memory_string_to_number) +{ + test_runner::_memory_fail_threshold = 4096 + 128; + + CHECK_XPATH_FAIL(STR("0.11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111")); +} + #endif |