diff options
| author | arseny.kapoulkine <arseny.kapoulkine@99668b35-9821-0410-8761-19e4c4f06640> | 2010-09-01 17:01:55 +0000 | 
|---|---|---|
| committer | arseny.kapoulkine <arseny.kapoulkine@99668b35-9821-0410-8761-19e4c4f06640> | 2010-09-01 17:01:55 +0000 | 
| commit | 42517f26a9f145fd2c1759b77218f28b11a9ee1a (patch) | |
| tree | 4e0e500c191b083e160f02aff5c1b6b8871b997e | |
| parent | 9a6549e802f9864d1e541be8117e6cf698e1fef5 (diff) | |
XPath: Don't use longjmp at all if exceptions are enabled; this solves all problems with GCC SJLJ exceptions
git-svn-id: http://pugixml.googlecode.com/svn/trunk@714 99668b35-9821-0410-8761-19e4c4f06640
| -rw-r--r-- | src/pugixml.cpp | 89 | 
1 files changed, 55 insertions, 34 deletions
| diff --git a/src/pugixml.cpp b/src/pugixml.cpp index b6d25a7..0e519a4 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -153,6 +153,34 @@ namespace  #endif  } +#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH) +// auto_ptr-like buffer holder for exception recovery +namespace +{ +	struct buffer_holder +	{ +		void* data; +		void (*deleter)(void*); + +		buffer_holder(void* data, void (*deleter)(void*)): data(data), deleter(deleter) +		{ +		} + +		~buffer_holder() +		{ +			if (data) deleter(data); +		} + +		void* release() +		{ +			void* result = data; +			data = 0; +			return result; +		} +	}; +} +#endif +  namespace pugi  {  	static const size_t xml_memory_page_size = 32768; @@ -2938,27 +2966,6 @@ namespace  	}  #ifndef PUGIXML_NO_STL -	struct buffer_holder -	{ -		void* data; - -		buffer_holder(void* data): data(data) -		{ -		} - -		~buffer_holder() -		{ -			if (data) global_deallocate(data); -		} - -		void* release() -		{ -			void* result = data; -			data = 0; -			return result; -		} -	}; -  	template <typename T> xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding)  	{  		// get length of remaining data in stream @@ -2975,7 +2982,7 @@ namespace  		if (static_cast<std::streamsize>(read_length) != length || length < 0) return make_parse_result(status_out_of_memory);  		// read stream data into memory (guard against stream exceptions with buffer holder) -		buffer_holder buffer = global_allocate((read_length > 0 ? read_length : 1) * sizeof(T)); +		buffer_holder buffer(global_allocate((read_length > 0 ? read_length : 1) * sizeof(T)), global_deallocate);  		if (!buffer.data) return make_parse_result(status_out_of_memory);  		stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length)); @@ -5645,11 +5652,13 @@ namespace pugi  			return new (memory) xpath_allocator();  		} -		static void destroy(xpath_allocator* alloc) +		static void destroy(void* ptr)  		{ -			if (!alloc) return; +			if (!ptr) return;  			// free all allocated pages +			xpath_allocator* alloc = static_cast<xpath_allocator*>(ptr); +  			memory_block* cur = alloc->_root;  			memory_block* first = &alloc->_first; @@ -7682,7 +7691,10 @@ namespace pugi  		xpath_variable_set* _variables;  		xpath_parse_result* _result; + +	#ifdef PUGIXML_NO_EXCEPTIONS  		jmp_buf _error_handler; +	#endif  		xpath_parser(const xpath_parser&);  		xpath_parser& operator=(const xpath_parser&); @@ -7692,7 +7704,11 @@ namespace pugi  			_result->error = message;  			_result->offset = _lexer.current_pos() - _query; +		#ifdef PUGIXML_NO_EXCEPTIONS  			longjmp(_error_handler, 1); +		#else +			throw xpath_exception(*_result); +		#endif  		}  		void* alloc_node() @@ -8504,9 +8520,13 @@ namespace pugi  		{  			xpath_parser parser(query, variables, alloc, result); +		#ifdef PUGIXML_NO_EXCEPTIONS  			int error = setjmp(parser._error_handler);  			return (error == 0) ? parser.parse() : 0; +		#else +			return parser.parse(); +		#endif  		}  	}; @@ -8702,25 +8722,26 @@ namespace pugi  		_result.error = 0;  		_result.offset = 0; -		_alloc = xpath_allocator::create(); +		xpath_allocator* alloc = xpath_allocator::create(); -		if (!_alloc) +		if (!alloc)  		{  			_result.error = "Out of memory"; + +		#ifndef PUGIXML_NO_EXCEPTIONS +			throw xpath_exception(_result); +		#endif  		}  		else  		{ -			_root = xpath_parser::parse(query, variables, *_alloc, &_result); -		} +			buffer_holder alloc_holder(alloc, xpath_allocator::destroy); -		if (!_root) -		{ -			xpath_allocator::destroy(_alloc); -			_alloc = 0; +			_root = xpath_parser::parse(query, variables, *alloc, &_result); -		#ifndef PUGIXML_NO_EXCEPTIONS -			throw xpath_exception(_result); +		#ifdef PUGIXML_NO_EXCEPTIONS +			if (_root) // only store allocator if parsing was a success  		#endif +			_alloc = static_cast<xpath_allocator*>(alloc_holder.release());  		}  	} | 
