From bc1e444694427d599710107d3e6b62165380b0b6 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Mon, 30 Jan 2017 08:52:32 -0800
Subject: XPath: Track allocation errors more explicitly

Any time an allocation fails xpath_allocator can set an externally
provided bool. The plan is to keep this bool up until evaluation ends,
so that we can use it to discard the potentially malformed result.
---
 src/pugixml.cpp | 28 ++++++++++++++++++++--------
 1 file changed, 20 insertions(+), 8 deletions(-)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 6b9fc89..396061a 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -7396,13 +7396,14 @@ PUGI__NS_BEGIN
 	{
 		xpath_memory_block* _root;
 		size_t _root_size;
+		bool* _error;
 
 	public:
 	#ifdef PUGIXML_NO_EXCEPTIONS
 		jmp_buf* error_handler;
 	#endif
 
-		xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size)
+		xpath_allocator(xpath_memory_block* root, bool* error = 0): _root(root), _root_size(0), _error(error)
 		{
 		#ifdef PUGIXML_NO_EXCEPTIONS
 			error_handler = 0;
@@ -7430,7 +7431,11 @@ PUGI__NS_BEGIN
 				size_t block_size = block_capacity + offsetof(xpath_memory_block, data);
 
 				xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size));
-				if (!block) return 0;
+				if (!block)
+				{
+					if (_error) *_error = true;
+					return 0;
+				}
 
 				block->next = _root;
 				block->capacity = block_capacity;
@@ -7579,6 +7584,7 @@ PUGI__NS_BEGIN
 
 	struct xpath_stack_data
 	{
+		bool error;
 		xpath_memory_block blocks[2];
 		xpath_allocator result;
 		xpath_allocator temp;
@@ -7588,7 +7594,7 @@ PUGI__NS_BEGIN
 		jmp_buf error_handler;
 	#endif
 
-		xpath_stack_data(): result(blocks + 0), temp(blocks + 1)
+		xpath_stack_data(): error(false), result(blocks + 0, &error), temp(blocks + 1, &error)
 		{
 			blocks[0].next = blocks[1].next = 0;
 			blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data);
@@ -11856,7 +11862,9 @@ PUGI__NS_BEGIN
 
 		xpath_context c(n, 1, 1);
 
-		return impl->root->eval_string(c, sd.stack);
+		xpath_string r = impl->root->eval_string(c, sd.stack);
+
+		return sd.error ? xpath_string() : r;
 	}
 
 	PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl)
@@ -12494,7 +12502,9 @@ namespace pugi
 		if (setjmp(sd.error_handler)) return false;
 	#endif
 
-		return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);
+		bool r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);
+
+		return sd.error ? false : r;
 	}
 
 	PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const
@@ -12508,7 +12518,9 @@ namespace pugi
 		if (setjmp(sd.error_handler)) return impl::gen_nan();
 	#endif
 
-		return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);
+		double r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);
+
+		return sd.error ? impl::gen_nan() : r;
 	}
 
 #ifndef PUGIXML_NO_STL
@@ -12556,7 +12568,7 @@ namespace pugi
 
 		impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all);
 
-		return xpath_node_set(r.begin(), r.end(), r.type());
+		return sd.error ? xpath_node_set() : xpath_node_set(r.begin(), r.end(), r.type());
 	}
 
 	PUGI__FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const
@@ -12573,7 +12585,7 @@ namespace pugi
 
 		impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first);
 
-		return r.first();
+		return sd.error ? xpath_node() : r.first();
 	}
 
 	PUGI__FN const xpath_parse_result& xpath_query::result() const
-- 
cgit v1.2.3