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 | 
