diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 965d8dabb..533d42cbd 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -165,6 +165,7 @@ if ! $(BOOST_ARCHIVE_LIST) { [ test-bsl-run test_xml_save_during_unwind ] [ test-bsl-run test_xml_escape_boundary : : ../build//boost_wserialization : [ requires std_wstreambuf ] ] [ test-bsl-run test_xml_trailing_whitespace ] + [ test-bsl-run test_xml_destroy_after_caught_error ] [ test-bsl-run test_xml_missing_nvp ] [ test-bsl-run test_mult_archive_types : : : [ requires std_wstreambuf ] ] [ test-bsl-run test_iterators : : : [ requires std_wstreambuf ] ] diff --git a/test/test_xml_destroy_after_caught_error.cpp b/test/test_xml_destroy_after_caught_error.cpp new file mode 100644 index 000000000..834b468d1 --- /dev/null +++ b/test/test_xml_destroy_after_caught_error.cpp @@ -0,0 +1,74 @@ +/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 +// test_xml_destroy_after_caught_error.cpp + +// Copyright 2026 Gennaro Prota. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +// Asking an XML input archive for a name which is not there throws, and the +// caller is entitled to catch that and carry on. The failed read has by +// then consumed the closing document tag, so the destructor finds end of +// input where it expected the trailer. That is normal termination, not a +// stream error, and the (implicitly noexcept) destructor has to complete +// cleanly rather than terminate the process. + +// This is the route into windup() that issue #99 named but left untested: +// test_xml_trailing_whitespace covers a truncated archive, where the tag was +// never written, while here the archive is well formed and an earlier failed +// read ate the tag. The archive is destroyed normally, not while an +// exception is in flight. + +// Reported by tsondergaard in +// https://github.com/boostorg/serialization/issues/109, with a program this +// test follows closely. Thanks! + +#include +#include + +#include +#include +#include +#include + +#include "test_tools.hpp" + +int test_main(int /* argc */, char * /* argv */ []){ + std::string content; + { + std::ostringstream os; + { + boost::archive::xml_oarchive oa(os); + const int x = 42; + oa << boost::serialization::make_nvp("x", x); + } + content = os.str(); + } + + int y = 0; + bool threw = false; + { + std::istringstream is(content); + boost::archive::xml_iarchive ia(is); + ia >> boost::serialization::make_nvp("x", y); + + BOOST_TRY { + int z = 0; + ia >> boost::serialization::make_nvp("not_there", z); + } + BOOST_CATCH(const boost::archive::archive_exception &){ + threw = true; + } + BOOST_CATCH_END + + // `ia` is destroyed here, with the closing tag already eaten by the + // read which failed, and with no exception in flight. + } + + BOOST_CHECK(threw); + BOOST_CHECK(42 == y); + + return EXIT_SUCCESS; +}