Commit 12861530 authored by Daniel Trebbien's avatar Daniel Trebbien Committed by Kjell Ahlstedt

Introduce xmlpp::wrapped_exception

This is an internal class which is used by SaxParser and Validator to
save the exception object thrown by a handler method when the exception
does not derive from xmlpp::exception (e.g. std::exception). The Raise()
method of xmlpp::wrapped_exception calls std::rethrow_exception() to
rethrow the exception object thrown by the handler method.

Catching any exception object thrown by a handler method is important in
ensuring that we are able to reset the internal state, and, in the case
of SaxParser::parse(), that we restore the old _xmlSAXHandler pointer so
that we do not double-free the _xmlSAXHandler object held by SaxParser.

Fixes Bug 753570 - “double free or corruption” if a std::exception is thrown
https://bugzilla.gnome.org/show_bug.cgi?id=753570
parent b3155523
......@@ -68,6 +68,7 @@ stamp-h?
/examples/test-suite.log
# macros
/macros/compile
/macros/compile-binding.am
/macros/config.guess
/macros/config.sub
......@@ -83,3 +84,10 @@ stamp-h?
/macros/ltversion.m4
/macros/lt~obsolete.m4
/macros/missing
/macros/test-driver
# tests
/tests/*/test
/tests/*/test.log
/tests/*/test.trs
/tests/test-suite.log
SUBDIRS = . examples
SUBDIRS = . examples tests
ACLOCAL_AMFLAGS = -I macros ${ACLOCAL_FLAGS}
DISTCHECK_CONFIGURE_FLAGS = --enable-warnings=fatal
......@@ -82,6 +82,7 @@ cc_sources = libxml++/attribute.cc \
libxml++/exceptions/parse_error.cc \
libxml++/exceptions/validity_error.cc \
libxml++/exceptions/internal_error.cc \
libxml++/exceptions/wrapped_exception.cc \
libxml++/io/istreamparserinputbuffer.cc \
libxml++/io/outputbuffer.cc \
libxml++/io/ostreamoutputbuffer.cc \
......
......@@ -61,6 +61,7 @@ AC_DEFINE([LIBXMLCPP_EXCEPTIONS_ENABLED],[1], [This is always set. This is only
AC_CONFIG_FILES([Makefile
examples/Makefile
tests/Makefile
docs/reference/Doxyfile
MSVC_Net2005/libxml++/libxml++.rc
MSVC_Net2008/libxml++/libxml++.rc
......
/* Copyright (C) 2015 The libxml++ development team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "wrapped_exception.h"
namespace xmlpp
{
wrapped_exception::wrapped_exception(std::exception_ptr exception_ptr)
: exception("Wrapped exception"), exception_ptr_(exception_ptr)
{
}
wrapped_exception::~wrapped_exception() noexcept
{
}
void wrapped_exception::Raise() const
{
std::rethrow_exception(exception_ptr_);
}
exception* wrapped_exception::Clone() const
{
return new wrapped_exception(exception_ptr_);
}
} // namespace xmlpp
/* Copyright (C) 2015 The libxml++ development team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __LIBXMLPP_WRAPPED_EXCEPTION_H
#define __LIBXMLPP_WRAPPED_EXCEPTION_H
#include <exception>
#include <libxml++/exceptions/exception.h>
namespace xmlpp
{
class wrapped_exception : public exception
{
public:
explicit wrapped_exception(std::exception_ptr exception_ptr);
~wrapped_exception() noexcept override;
void Raise() const override;
exception* Clone() const override;
private:
std::exception_ptr exception_ptr_;
};
} // namespace xmlpp
#endif // __LIBXMLPP_WRAPPED_EXCEPTION_H
......@@ -8,6 +8,7 @@
// because it temporarily undefines G_DISABLE_DEPRECATED while it includes glib.h.
#include <glibmm/threads.h> // For Glib::Threads::Mutex. Needed until the next API/ABI break.
#include "libxml++/exceptions/wrapped_exception.h"
#include "libxml++/parsers/parser.h"
#include <libxml/parser.h>
......@@ -350,6 +351,10 @@ void Parser::callback_error_or_warning(MsgType msg_type, void* ctx,
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
}
}
......
......@@ -7,6 +7,7 @@
* 2002/01/21 Valentin Rusu - added CDATA handlers
*/
#include "libxml++/exceptions/wrapped_exception.h"
#include "libxml++/parsers/saxparser.h"
#include "libxml++/nodes/element.h"
#include "libxml++/keepblanks.h"
......@@ -384,7 +385,11 @@ xmlEntityPtr SaxParserCallback::get_entity(void* context, const xmlChar* name)
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
return result;
}
......@@ -406,6 +411,10 @@ void SaxParserCallback::entity_decl(void* context, const xmlChar* name, int type
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::start_document(void* context)
......@@ -421,6 +430,10 @@ void SaxParserCallback::start_document(void* context)
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::end_document(void* context)
......@@ -439,6 +452,10 @@ void SaxParserCallback::end_document(void* context)
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::start_element(void* context,
......@@ -463,6 +480,10 @@ void SaxParserCallback::start_element(void* context,
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::end_element(void* context, const xmlChar* name)
......@@ -478,6 +499,10 @@ void SaxParserCallback::end_element(void* context, const xmlChar* name)
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::characters(void * context, const xmlChar* ch, int len)
......@@ -499,6 +524,10 @@ void SaxParserCallback::characters(void * context, const xmlChar* ch, int len)
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::comment(void* context, const xmlChar* value)
......@@ -514,6 +543,10 @@ void SaxParserCallback::comment(void* context, const xmlChar* value)
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::warning(void* context, const char* fmt, ...)
......@@ -536,6 +569,10 @@ void SaxParserCallback::warning(void* context, const char* fmt, ...)
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::error(void* context, const char* fmt, ...)
......@@ -561,6 +598,10 @@ void SaxParserCallback::error(void* context, const char* fmt, ...)
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::fatal_error(void* context, const char* fmt, ...)
......@@ -583,6 +624,10 @@ void SaxParserCallback::fatal_error(void* context, const char* fmt, ...)
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::cdata_block(void* context, const xmlChar* value, int len)
......@@ -603,6 +648,10 @@ void SaxParserCallback::cdata_block(void* context, const xmlChar* value, int len
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
void SaxParserCallback::internal_subset(void* context, const xmlChar* name,
......@@ -622,6 +671,10 @@ void SaxParserCallback::internal_subset(void* context, const xmlChar* name,
{
parser->handleException(e);
}
catch(...)
{
parser->handleException(wrapped_exception(std::current_exception()));
}
}
} // namespace xmlpp
......@@ -5,6 +5,7 @@
* included with libxml++ as the file COPYING.
*/
#include "libxml++/exceptions/wrapped_exception.h"
#include "libxml++/validators/validator.h"
#include <libxml/parser.h>
......@@ -114,6 +115,10 @@ void Validator::callback_validity_error(void* valid_, const char* msg, ...)
{
validator->handleException(e);
}
catch(...)
{
validator->handleException(wrapped_exception(std::current_exception()));
}
}
}
......@@ -139,6 +144,10 @@ void Validator::callback_validity_warning(void* valid_, const char* msg, ...)
{
validator->handleException(e);
}
catch(...)
{
validator->handleException(wrapped_exception(std::current_exception()));
}
}
}
......
## Copyright (C) 2015 The libxml++ development team
##
## This library is free software; you can redistribute it and/or
## modify it under the terms of the GNU Lesser General Public
## License as published by the Free Software Foundation; either
## version 2.1 of the License, or (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public
## License along with this library; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) -I. $(LIBXMLXX_CFLAGS)
AM_CXXFLAGS = $(LIBXMLXX_WXXFLAGS)
LDADD = $(top_builddir)/libxml++/libxml++-$(LIBXMLXX_API_VERSION).la $(LIBXMLXX_LIBS)
check_PROGRAMS = \
saxparser_chunk_parsing_inconsistent_state/test \
saxparser_parse_double_free/test \
saxparser_parse_stream_inconsistent_state/test
TESTS = $(check_PROGRAMS)
saxparser_chunk_parsing_inconsistent_state_test_SOURCES = saxparser_chunk_parsing_inconsistent_state/main.cc
saxparser_parse_double_free_test_SOURCES = saxparser_parse_double_free/main.cc
saxparser_parse_stream_inconsistent_state_test_SOURCES = saxparser_parse_stream_inconsistent_state/main.cc
/* Copyright (C) 2015 The libxml++ development team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cstdlib>
#include <glibmm.h>
#include <sstream>
#include <stdexcept>
#include <libxml++/libxml++.h>
class MySaxParser : public xmlpp::SaxParser
{
protected:
void on_start_document() override
{
throw std::runtime_error("some custom runtime exception");
}
void on_error(const Glib::ustring& text) override
{
throw std::runtime_error("on_error() called");
}
};
int main()
{
Glib::init();
{
MySaxParser parser;
bool exceptionThrown = false;
try
{
parser.parse_chunk("<?");
parser.finish_chunk_parsing();
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_error() called");
}
g_assert_true(exceptionThrown);
// Try parsing a stream now.
exceptionThrown = false;
try
{
std::stringstream ss("<root></root>");
parser.parse_stream(ss);
}
catch(const xmlpp::parse_error& e)
{
// An "Attempt to start a second parse while a parse is in progress." parse
// error should not have been thrown.
g_assert_not_reached();
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "some custom runtime exception");
}
g_assert_true(exceptionThrown);
}
return EXIT_SUCCESS;
}
/* Copyright (C) 2015 The libxml++ development team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cstdlib>
#include <glibmm.h>
#include <stdexcept>
#include <libxml++/libxml++.h>
class OnCdataBlockTestParser : public xmlpp::SaxParser
{
protected:
void on_cdata_block(const Glib::ustring& text) override
{
g_assert_cmpstr(text.c_str(), ==, "some CDATA");
throw std::runtime_error("on_cdata_block runtime exception");
}
};
void test_on_cdata_block()
{
OnCdataBlockTestParser parser;
bool exceptionThrown = false;
try
{
parser.parse_memory("<root><![CDATA[some CDATA]]></root>");
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_cdata_block runtime exception");
}
g_assert_true(exceptionThrown);
}
class OnCharactersTestParser : public xmlpp::SaxParser
{
protected:
void on_characters(const Glib::ustring& characters) override
{
g_assert_cmpstr(characters.c_str(), ==, "abc");
throw std::runtime_error("on_characters runtime exception");
}
};
void test_on_characters()
{
OnCharactersTestParser parser;
bool exceptionThrown = false;
try
{
parser.parse_memory("<root>abc</root>");
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_characters runtime exception");
}
g_assert_true(exceptionThrown);
}
class OnCommentTestParser : public xmlpp::SaxParser
{
protected:
void on_comment(const Glib::ustring& text) override
{
g_assert_cmpstr(text.c_str(), ==, "a comment");
throw std::runtime_error("on_comment runtime exception");
}
};
void test_on_comment()
{
OnCommentTestParser parser;
bool exceptionThrown = false;
try
{
parser.parse_memory("<root><!--a comment--></root>");
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_comment runtime exception");
}
g_assert_true(exceptionThrown);
}
class OnEndDocumentTestParser : public xmlpp::SaxParser
{
protected:
void on_end_document() override
{
throw std::runtime_error("on_end_document runtime exception");
}
};
void test_on_end_document()
{
OnEndDocumentTestParser parser;
bool exceptionThrown = false;
try
{
parser.parse_memory("<root></root>");
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_end_document runtime exception");
}
g_assert_true(exceptionThrown);
}
class OnEndElementTestParser : public xmlpp::SaxParser
{
protected:
void on_end_element(const Glib::ustring& name) override
{
g_assert_cmpstr(name.c_str(), ==, "a:root");
throw std::runtime_error("on_end_element runtime exception");
}
};
void test_on_end_element()
{
OnEndElementTestParser parser;
bool exceptionThrown = false;
try
{
parser.parse_memory("<a:root xmlns:a=\"urn:test\"></a:root>");
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_end_element runtime exception");
}
g_assert_true(exceptionThrown);
}
class OnEntityDeclarationTestParser : public xmlpp::SaxParser
{
protected:
void on_entity_declaration(const Glib::ustring& name, xmlpp::XmlEntityType type, const Glib::ustring& publicId, const Glib::ustring& systemId, const Glib::ustring& content) override
{
g_assert_cmpstr(name.c_str(), ==, "number");
g_assert_cmpstr(content.c_str(), ==, "42");
throw std::runtime_error("on_entity_declaration runtime exception");
}
};
void test_on_entity_declaration()
{
OnEntityDeclarationTestParser parser;
bool exceptionThrown = false;
try
{
parser.parse_memory("<!DOCTYPE MyDocument [<!ENTITY number \"42\">]><root></root>");
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_entity_declaration runtime exception");
}
g_assert_true(exceptionThrown);
}
class OnErrorTestParser : public xmlpp::SaxParser
{
protected:
void on_error(const Glib::ustring& text) override
{
throw std::runtime_error("on_error runtime exception");
}
};
void test_on_error()
{
OnErrorTestParser parser;
bool exceptionThrown = false;
try
{
parser.parse_memory("<root>&unknown;</root>");
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_error runtime exception");
}
g_assert_true(exceptionThrown);
}
class OnGetEntityTestParser : public xmlpp::SaxParser
{
public:
OnGetEntityTestParser()
: xmlpp::SaxParser(true)
{
}
protected:
_xmlEntity* on_get_entity(const Glib::ustring& name) override
{
g_assert_cmpstr(name.c_str(), ==, "number");
throw std::runtime_error("on_get_entity runtime exception");
}
};
void test_on_get_entity()
{
OnGetEntityTestParser parser;
bool exceptionThrown = false;
try
{
parser.parse_memory("<!DOCTYPE MyDocument [<!ENTITY number \"42\">]><root>&number;</root>");
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_get_entity runtime exception");
}
g_assert_true(exceptionThrown);
}
class OnStartDocumentTestParser : public xmlpp::SaxParser
{
protected:
void on_start_document() override
{
throw std::runtime_error("on_start_document runtime exception");
}
};
void test_on_start_document()
{
OnStartDocumentTestParser parser;
bool exceptionThrown = false;
try
{
parser.parse_memory("<root></root>");
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_start_document runtime exception");
}
g_assert_true(exceptionThrown);
}
class OnStartElementTestParser : public xmlpp::SaxParser
{
protected:
void on_start_element(const Glib::ustring& name, const xmlpp::SaxParser::AttributeList& attributes) override
{
g_assert_cmpstr(name.c_str(), ==, "b:root");
g_assert_cmpint(attributes.size(), ==, 2);
throw std::runtime_error("on_start_element runtime exception");
}
};
void test_on_start_element()
{
OnStartElementTestParser parser;
bool exceptionThrown = false;
try
{
parser.parse_memory("<b:root xmlns:b=\"urn:test\" someattr=\"test\"></b:root>");
}
catch(const std::runtime_error& e)
{
exceptionThrown = true;
g_assert_cmpstr(e.what(), ==, "on_start_element runtime exception");
}
g_assert_true(exceptionThrown);
}
int main()
{
Glib::init();
test_on_cdata_block();