XPath: Correct out of memory handling for string to number conversion during parsing, added corresponding test

git-svn-id: http://pugixml.googlecode.com/svn/trunk@651 99668b35-9821-0410-8761-19e4c4f06640
This commit is contained in:
arseny.kapoulkine 2010-08-29 15:16:55 +00:00
parent 6a9d59e907
commit 1f74bf1edc
2 changed files with 31 additions and 23 deletions

View File

@ -497,35 +497,30 @@ namespace
#endif #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]; char_t buffer[32];
size_t length = static_cast<size_t>(end - begin); size_t length = static_cast<size_t>(end - begin);
char_t* scratch = buffer;
if (length < sizeof(buffer) / sizeof(buffer[0])) 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
{ {
// need to make dummy on-heap copy // need to make dummy on-heap copy
char_t* copy = static_cast<char_t*>(get_memory_allocation_function()((length + 1) * sizeof(char_t))); scratch = static_cast<char_t*>(get_memory_allocation_function()((length + 1) * sizeof(char_t)));
if (!copy) return gen_nan(); // $$ out of memory if (!scratch) return false;
memcpy(copy, begin, length * sizeof(char_t));
copy[length] = 0;
double result = convert_string_to_number(copy);
get_memory_deallocation_function()(copy);
return result;
} }
// copy string to zero-terminated buffer and perform conversion
memcpy(scratch, begin, length * sizeof(char_t));
scratch[length] = 0;
*out_result = convert_string_to_number(scratch);
// free dummy buffer
if (scratch != buffer) get_memory_deallocation_function()(scratch);
return true;
} }
double round_nearest(double value) double round_nearest(double value)
@ -2899,7 +2894,10 @@ namespace pugi
case lex_number: 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); xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value);
_lexer.next(); _lexer.next();

View File

@ -269,15 +269,25 @@ TEST_XML(xpath_parse_absolute, "<div><s/></div>")
CHECK_XPATH_NODESET(doc, STR("/*[/]")) % 2; 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; test_runner::_memory_fail_threshold = 1;
CHECK_XPATH_FAIL(STR("1")); CHECK_XPATH_FAIL(STR("1"));
}
TEST(xpath_parse_out_of_memory_second_page_node)
{
test_runner::_memory_fail_threshold = 8192; 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")); 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 #endif