[libxml++/libxml++-2-40] Work around some platforms' lack of support for std::exception_ptr



commit 4ec9236770c3918ef4393e37ce6a269b21b95ab7
Author: Daniel Trebbien <dtrebbien gmail com>
Date:   Mon Oct 26 18:46:28 2015 +0100

    Work around some platforms' lack of support for std::exception_ptr
    
    * libxml++/exceptions/wrapped_exception.[cc|h]: Declare the wrapped_exception
    class only if LIBXMLXX_HAVE_EXCEPTION_PTR is defined.
    * libxml++/parsers/parser.[cc|h]:
    * libxml++/parsers/saxparser.cc: Add Parser::handle_exception(), and call
    it instead the handleException().
    * libxml++/validators/validator.[cc|h]: Add Validator::handle_exception(),
    and call it instead the handleException().
    * tests/saxparser_chunk_parsing_inconsistent_state/main.cc:
    * tests/saxparser_parse_double_free/main.cc:
    * tests/saxparser_parse_stream_inconsistent_state/main.cc: Catch
    xmlpp::exception, if LIBXMLXX_HAVE_EXCEPTION_PTR is not defined.
    Bug #757042.
    
    Kjell Ahlstedt <kjell ahlstedt bredband net> added handle_exception() and
    modified Daniel Trebbien's patch to fit with the previous commit.

 libxml++/exceptions/wrapped_exception.cc           |    4 +
 libxml++/exceptions/wrapped_exception.h            |   11 +-
 libxml++/parsers/parser.cc                         |   44 +++++++-
 libxml++/parsers/parser.h                          |    4 +
 libxml++/parsers/saxparser.cc                      |  104 +++++---------------
 libxml++/validators/validator.cc                   |   58 +++++++++---
 libxml++/validators/validator.h                    |    4 +
 .../main.cc                                        |   13 ++-
 tests/saxparser_parse_double_free/main.cc          |   46 ++++++++-
 .../main.cc                                        |   13 ++-
 10 files changed, 192 insertions(+), 109 deletions(-)
---
diff --git a/libxml++/exceptions/wrapped_exception.cc b/libxml++/exceptions/wrapped_exception.cc
index 8799e74..e82dd70 100644
--- a/libxml++/exceptions/wrapped_exception.cc
+++ b/libxml++/exceptions/wrapped_exception.cc
@@ -20,6 +20,8 @@
 namespace xmlpp
 {
 
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
+
 wrapped_exception::wrapped_exception(std::exception_ptr exception_ptr)
   : exception("Wrapped exception"), exception_ptr_(exception_ptr)
 {
@@ -39,4 +41,6 @@ exception* wrapped_exception::Clone() const
   return new wrapped_exception(exception_ptr_);
 }
 
+#endif // LIBXMLXX_HAVE_EXCEPTION_PTR
+
 } // namespace xmlpp
diff --git a/libxml++/exceptions/wrapped_exception.h b/libxml++/exceptions/wrapped_exception.h
index 6fa7bac..3738680 100644
--- a/libxml++/exceptions/wrapped_exception.h
+++ b/libxml++/exceptions/wrapped_exception.h
@@ -21,17 +21,14 @@
 #include <exception>
 
 #include <libxml++/exceptions/exception.h>
+#include <libxml++config.h>
 
 namespace xmlpp
 {
 
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-//TODO: At the next ABI break, consider changing
-//   exception* exception_;
-// to
-//   std::exception_ptr exception_ptr_;
-// in xmlpp::Parser and xmlpp::Validator, and removing xmlpp::wrapped_exception.
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
 
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
 /** Helper class for propagating an exception through C code.
  * Should not be used by applications.
  *
@@ -51,6 +48,8 @@ private:
 };
 #endif //DOXYGEN_SHOULD_SKIP_THIS
 
+#endif // LIBXMLXX_HAVE_EXCEPTION_PTR
+
 } // namespace xmlpp
 
 #endif // __LIBXMLPP_WRAPPED_EXCEPTION_H
diff --git a/libxml++/parsers/parser.cc b/libxml++/parsers/parser.cc
index bd3865c..b96fe90 100644
--- a/libxml++/parsers/parser.cc
+++ b/libxml++/parsers/parser.cc
@@ -347,13 +347,9 @@ void Parser::callback_error_or_warning(MsgType msg_type, void* ctx,
             break;
         }
       }
-      catch(const exception& e)
+      catch (...)
       {
-        parser->handleException(e);
-      }
-      catch(...)
-      {
-        parser->handleException(wrapped_exception(std::current_exception()));
+        parser->handle_exception();
       }
     }
   }
@@ -370,6 +366,42 @@ void Parser::handleException(const exception& e)
   //release_underlying();
 }
 
+void Parser::handle_exception()
+{
+  delete exception_;
+  exception_ = nullptr;
+
+  try
+  {
+    throw; // Rethrow current exception
+  }
+  catch (const exception& e)
+  {
+    exception_ = e.Clone();
+  }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
+  catch (...)
+  {
+    exception_ = new wrapped_exception(std::current_exception());
+  }
+#else
+  catch (const std::exception& e)
+  {
+    exception_ = new exception(e.what());
+  }
+  catch (...)
+  {
+    exception_ = new exception("An exception was thrown that is not derived from std::exception or 
xmlpp::exception.\n"
+      "It could not be caught and rethrown because this platform does not support std::exception_ptr.");
+  }
+#endif
+
+  if (context_)
+    xmlStopParser(context_);
+
+  //release_underlying();
+}
+
 void Parser::check_for_exception()
 {
   check_for_validity_messages();
diff --git a/libxml++/parsers/parser.h b/libxml++/parsers/parser.h
index 96034af..97c49df 100644
--- a/libxml++/parsers/parser.h
+++ b/libxml++/parsers/parser.h
@@ -162,7 +162,11 @@ protected:
   virtual void on_validity_error(const Glib::ustring& message);
   virtual void on_validity_warning(const Glib::ustring& message);
 
+  //TODO: When we can break ABI/API, remove handleException() and make
+  // handle_exception() virtual.
   virtual void handleException(const exception& e);
+  /// To be called in an exception handler.
+  void handle_exception();
   virtual void check_for_exception();
 
   //TODO: In a future API/ABI-break, change the name of this function to
diff --git a/libxml++/parsers/saxparser.cc b/libxml++/parsers/saxparser.cc
index adb2570..b7cf5ab 100644
--- a/libxml++/parsers/saxparser.cc
+++ b/libxml++/parsers/saxparser.cc
@@ -381,13 +381,9 @@ xmlEntityPtr SaxParserCallback::get_entity(void* context, const xmlChar* name)
   {
     result = parser->on_get_entity((const char*)name);
   }
-  catch(const exception& e)
+  catch (...)
   {
-    parser->handleException(e);
-  }
-  catch(...)
-  {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 
   return result;
@@ -407,13 +403,9 @@ void SaxParserCallback::entity_decl(void* context, const xmlChar* name, int type
       ( systemId ? Glib::ustring((const char*)systemId) : ""),
       ( content ? Glib::ustring((const char*)content) : "") );
   }
-  catch(const exception& e)
-  {
-    parser->handleException(e);
-  }
-  catch(...)
+  catch (...)
   {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -426,13 +418,9 @@ void SaxParserCallback::start_document(void* context)
   {
     parser->on_start_document();
   }
-  catch(const exception& e)
+  catch (...)
   {
-    parser->handleException(e);
-  }
-  catch(...)
-  {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -448,13 +436,9 @@ void SaxParserCallback::end_document(void* context)
   {
     parser->on_end_document();
   }
-  catch(const exception& e)
+  catch (...)
   {
-    parser->handleException(e);
-  }
-  catch(...)
-  {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -476,13 +460,9 @@ void SaxParserCallback::start_element(void* context,
   {
     parser->on_start_element(Glib::ustring((const char*) name), attributes);
   }
-  catch(const exception& e)
-  {
-    parser->handleException(e);
-  }
-  catch(...)
+  catch (...)
   {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -495,13 +475,9 @@ void SaxParserCallback::end_element(void* context, const xmlChar* name)
   {
     parser->on_end_element(Glib::ustring((const char*) name));
   }
-  catch(const exception& e)
+  catch (...)
   {
-    parser->handleException(e);
-  }
-  catch(...)
-  {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -520,13 +496,9 @@ void SaxParserCallback::characters(void * context, const xmlChar* ch, int len)
           reinterpret_cast<const char *>(ch),
           reinterpret_cast<const char *>(ch + len) ) );
   }
-  catch(const exception& e)
-  {
-    parser->handleException(e);
-  }
-  catch(...)
+  catch (...)
   {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -539,13 +511,9 @@ void SaxParserCallback::comment(void* context, const xmlChar* value)
   {
     parser->on_comment(Glib::ustring((const char*) value));
   }
-  catch(const exception& e)
-  {
-    parser->handleException(e);
-  }
-  catch(...)
+  catch (...)
   {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -565,13 +533,9 @@ void SaxParserCallback::warning(void* context, const char* fmt, ...)
   {
     parser->on_warning(Glib::ustring(buff));
   }
-  catch(const exception& e)
+  catch (...)
   {
-    parser->handleException(e);
-  }
-  catch(...)
-  {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -594,13 +558,9 @@ void SaxParserCallback::error(void* context, const char* fmt, ...)
   {
     parser->on_error(Glib::ustring(buff));
   }
-  catch(const exception& e)
-  {
-    parser->handleException(e);
-  }
-  catch(...)
+  catch (...)
   {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -620,13 +580,9 @@ void SaxParserCallback::fatal_error(void* context, const char* fmt, ...)
   {
     parser->on_fatal_error(Glib::ustring(buff));
   }
-  catch(const exception& e)
+  catch (...)
   {
-    parser->handleException(e);
-  }
-  catch(...)
-  {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -644,13 +600,9 @@ void SaxParserCallback::cdata_block(void* context, const xmlChar* value, int len
           reinterpret_cast<const char *>(value),
           reinterpret_cast<const char *>(value + len) ) );
   }
-  catch(const exception& e)
-  {
-    parser->handleException(e);
-  }
-  catch(...)
+  catch (...)
   {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
@@ -667,13 +619,9 @@ void SaxParserCallback::internal_subset(void* context, const xmlChar* name,
 
     parser->on_internal_subset( Glib::ustring((const char*) name), pid, sid);
   }
-  catch(const exception& e)
-  {
-    parser->handleException(e);
-  }
-  catch(...)
+  catch (...)
   {
-    parser->handleException(wrapped_exception(std::current_exception()));
+    parser->handle_exception();
   }
 }
 
diff --git a/libxml++/validators/validator.cc b/libxml++/validators/validator.cc
index 220d459..8e7a837 100644
--- a/libxml++/validators/validator.cc
+++ b/libxml++/validators/validator.cc
@@ -111,13 +111,9 @@ void Validator::callback_validity_error(void* valid_, const char* msg, ...)
     {
       validator->on_validity_error(Glib::ustring(buff));
     }
-    catch(const exception& e)
+    catch (...)
     {
-      validator->handleException(e);
-    }
-    catch(...)
-    {
-      validator->handleException(wrapped_exception(std::current_exception()));
+      validator->handle_exception();
     }
   }
 }
@@ -140,13 +136,9 @@ void Validator::callback_validity_warning(void* valid_, const char* msg, ...)
     {
       validator->on_validity_warning(Glib::ustring(buff));
     }
-    catch(const exception& e)
-    {
-      validator->handleException(e);
-    }
-    catch(...)
+    catch (...)
     {
-      validator->handleException(wrapped_exception(std::current_exception()));
+      validator->handle_exception();
     }
   }
 }
@@ -168,6 +160,48 @@ void Validator::handleException(const exception& e)
   //release_underlying();
 }
 
+void Validator::handle_exception()
+{
+  delete exception_;
+  exception_ = nullptr;
+
+  try
+  {
+    throw; // Rethrow current exception
+  }
+  catch (const exception& e)
+  {
+    exception_ = e.Clone();
+  }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
+  catch (...)
+  {
+    exception_ = new wrapped_exception(std::current_exception());
+  }
+#else
+  catch (const std::exception& e)
+  {
+    exception_ = new exception(e.what());
+  }
+  catch (...)
+  {
+    exception_ = new exception("An exception was thrown that is not derived from std::exception or 
xmlpp::exception.\n"
+      "It could not be caught and rethrown because this platform does not support std::exception_ptr.");
+  }
+#endif
+
+  // Don't delete the DTD validation context or schema validation context
+  // while validating. It would cause accesses to deallocated memory in libxml2
+  // functions after the return from Validator::callback_validity_...().
+  // Parser::handle_exception() calls xmlStopParser(), but there is no
+  // xmlStopValidator() or similar function to call here.
+  // We don't throw the exception here, since it would have to pass through
+  // C functions. That's not guaranteed to work. It might work, but it depends
+  // on the C compiler and the options used when building libxml2.
+
+  //release_underlying();
+}
+
 void Validator::check_for_exception()
 {
   check_for_validity_messages();
diff --git a/libxml++/validators/validator.h b/libxml++/validators/validator.h
index cdf9f2f..6d4a5d8 100644
--- a/libxml++/validators/validator.h
+++ b/libxml++/validators/validator.h
@@ -37,7 +37,11 @@ protected:
   virtual void on_validity_error(const Glib::ustring& message);
   virtual void on_validity_warning(const Glib::ustring& message);
 
+  //TODO: When we can break ABI/API, remove handleException() and make
+  // handle_exception() virtual.
   virtual void handleException(const exception& e);
+  /// To be called in an exception handler.
+  void handle_exception();
   virtual void check_for_exception();
   virtual void check_for_validity_messages();
 
diff --git a/tests/saxparser_chunk_parsing_inconsistent_state/main.cc 
b/tests/saxparser_chunk_parsing_inconsistent_state/main.cc
index 5e34233..136bfb7 100644
--- a/tests/saxparser_chunk_parsing_inconsistent_state/main.cc
+++ b/tests/saxparser_chunk_parsing_inconsistent_state/main.cc
@@ -15,13 +15,14 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <config.h>
+#include <libxml++/libxml++.h>
+
 #include <cstdlib>
 #include <glibmm.h>
 #include <sstream>
 #include <stdexcept>
 
-#include <libxml++/libxml++.h>
-
 class MySaxParser : public xmlpp::SaxParser
 {
 protected:
@@ -48,7 +49,11 @@ int main()
       parser.parse_chunk("<?");
       parser.finish_chunk_parsing();
     }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
     catch(const std::runtime_error& e)
+#else
+    catch(const xmlpp::exception& e)
+#endif
     {
       exceptionThrown = true;
       g_assert_cmpstr(e.what(), ==, "on_error() called");
@@ -68,7 +73,11 @@ int main()
       // error should not have been thrown.
       g_assert_not_reached();
     }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
     catch(const std::runtime_error& e)
+#else
+    catch(const xmlpp::exception& e)
+#endif
     {
       exceptionThrown = true;
       g_assert_cmpstr(e.what(), ==, "some custom runtime exception");
diff --git a/tests/saxparser_parse_double_free/main.cc b/tests/saxparser_parse_double_free/main.cc
index faaf964..e1bd3b6 100644
--- a/tests/saxparser_parse_double_free/main.cc
+++ b/tests/saxparser_parse_double_free/main.cc
@@ -15,13 +15,13 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <config.h>
+#include <libxml++/libxml++.h>
+
 #include <cstdlib>
 #include <glibmm.h>
 #include <stdexcept>
 
-#include <libxml++/libxml++.h>
-
-
 class OnCdataBlockTestParser : public xmlpp::SaxParser
 {
 protected:
@@ -40,7 +40,11 @@ void test_on_cdata_block()
   {
     parser.parse_memory("<root><![CDATA[some CDATA]]></root>");
   }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
   catch(const std::runtime_error& e)
+#else
+  catch(const xmlpp::exception& e)
+#endif
   {
     exceptionThrown = true;
     g_assert_cmpstr(e.what(), ==, "on_cdata_block runtime exception");
@@ -67,7 +71,11 @@ void test_on_characters()
   {
     parser.parse_memory("<root>abc</root>");
   }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
   catch(const std::runtime_error& e)
+#else
+  catch(const xmlpp::exception& e)
+#endif
   {
     exceptionThrown = true;
     g_assert_cmpstr(e.what(), ==, "on_characters runtime exception");
@@ -94,7 +102,11 @@ void test_on_comment()
   {
     parser.parse_memory("<root><!--a comment--></root>");
   }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
   catch(const std::runtime_error& e)
+#else
+  catch(const xmlpp::exception& e)
+#endif
   {
     exceptionThrown = true;
     g_assert_cmpstr(e.what(), ==, "on_comment runtime exception");
@@ -120,7 +132,11 @@ void test_on_end_document()
   {
     parser.parse_memory("<root></root>");
   }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
   catch(const std::runtime_error& e)
+#else
+  catch(const xmlpp::exception& e)
+#endif
   {
     exceptionThrown = true;
     g_assert_cmpstr(e.what(), ==, "on_end_document runtime exception");
@@ -147,7 +163,11 @@ void test_on_end_element()
   {
     parser.parse_memory("<a:root xmlns:a=\"urn:test\"></a:root>");
   }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
   catch(const std::runtime_error& e)
+#else
+  catch(const xmlpp::exception& e)
+#endif
   {
     exceptionThrown = true;
     g_assert_cmpstr(e.what(), ==, "on_end_element runtime exception");
@@ -177,7 +197,11 @@ void test_on_entity_declaration()
   {
     parser.parse_memory("<!DOCTYPE MyDocument [<!ENTITY number \"42\">]><root></root>");
   }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
   catch(const std::runtime_error& e)
+#else
+  catch(const xmlpp::exception& e)
+#endif
   {
     exceptionThrown = true;
     g_assert_cmpstr(e.what(), ==, "on_entity_declaration runtime exception");
@@ -203,7 +227,11 @@ void test_on_error()
   {
     parser.parse_memory("<root>&unknown;</root>");
   }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
   catch(const std::runtime_error& e)
+#else
+  catch(const xmlpp::exception& e)
+#endif
   {
     exceptionThrown = true;
     g_assert_cmpstr(e.what(), ==, "on_error runtime exception");
@@ -235,7 +263,11 @@ void test_on_get_entity()
   {
     parser.parse_memory("<!DOCTYPE MyDocument [<!ENTITY number \"42\">]><root>&number;</root>");
   }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
   catch(const std::runtime_error& e)
+#else
+  catch(const xmlpp::exception& e)
+#endif
   {
     exceptionThrown = true;
     g_assert_cmpstr(e.what(), ==, "on_get_entity runtime exception");
@@ -261,7 +293,11 @@ void test_on_start_document()
   {
     parser.parse_memory("<root></root>");
   }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
   catch(const std::runtime_error& e)
+#else
+  catch(const xmlpp::exception& e)
+#endif
   {
     exceptionThrown = true;
     g_assert_cmpstr(e.what(), ==, "on_start_document runtime exception");
@@ -289,7 +325,11 @@ void test_on_start_element()
   {
     parser.parse_memory("<b:root xmlns:b=\"urn:test\" someattr=\"test\"></b:root>");
   }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
   catch(const std::runtime_error& e)
+#else
+  catch(const xmlpp::exception& e)
+#endif
   {
     exceptionThrown = true;
     g_assert_cmpstr(e.what(), ==, "on_start_element runtime exception");
diff --git a/tests/saxparser_parse_stream_inconsistent_state/main.cc 
b/tests/saxparser_parse_stream_inconsistent_state/main.cc
index ea8cf44..4fd1320 100644
--- a/tests/saxparser_parse_stream_inconsistent_state/main.cc
+++ b/tests/saxparser_parse_stream_inconsistent_state/main.cc
@@ -15,13 +15,14 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <config.h>
+#include <libxml++/libxml++.h>
+
 #include <cstdlib>
 #include <glibmm.h>
 #include <sstream>
 #include <stdexcept>
 
-#include <libxml++/libxml++.h>
-
 class MySaxParser : public xmlpp::SaxParser
 {
 protected:
@@ -44,7 +45,11 @@ int main()
       std::stringstream ss("<root></root>");
       parser.parse_stream(ss);
     }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
     catch(const std::runtime_error& e)
+#else
+    catch(const xmlpp::exception& e)
+#endif
     {
       exceptionThrown = true;
       g_assert_cmpstr(e.what(), ==, "some custom runtime exception");
@@ -64,7 +69,11 @@ int main()
       // error should not have been thrown.
       g_assert_not_reached();
     }
+#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR
     catch(const std::runtime_error& e)
+#else
+    catch(const xmlpp::exception& e)
+#endif
     {
       exceptionThrown = true;
       g_assert_cmpstr(e.what(), ==, "some custom runtime exception");


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]