summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pugixpath.cpp36
-rw-r--r--tests/test_xpath_parse.cpp12
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