Opened 5 years ago

Last modified 5 years ago

#13354 new Bugs

xml_iarchive destructor calls abort()

Reported by: anonymous Owned by: Robert Ramey
Milestone: To Be Determined Component: serialization
Version: Boost 1.66.0 Severity: Problem
Keywords: Cc:

Description

In the following Unit Test from VS2017 15.5.2 with Boost 1.66.0 from vcpkg, boost::archive::xml_iarchive() is successfully used to load an integer. When it goes out of scope, its destructor calls abort().

#include "stdafx.h"
#include "CppUnitTest.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

#include <boost/archive/archive_exception.hpp>
#include <boost/serialization/variant.hpp>

#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>

#include <boost/serialization/split_member.hpp>

namespace UtilityLibTest
{
    class XmlArchiveTest
    {
    public:
        XmlArchiveTest() { m_value = 4; }

        int Value() const { return m_value; }
        void Value(const int v) { m_value = v; }
    private:
        friend class boost::serialization::access;

        void load(boost::archive::xml_iarchive & ar, unsigned int version)
        {
            ar & BOOST_SERIALIZATION_NVP(m_value);
        }
        void save(boost::archive::xml_oarchive & ar, unsigned int version) const
        {
            ar & BOOST_SERIALIZATION_NVP(m_value);
        }
        BOOST_SERIALIZATION_SPLIT_MEMBER()
            
    protected:
        int m_value;
    };

    TEST_CLASS(UnitTest1)
    {
    public:

        TEST_METHOD(XmlArchive_SaveLoad)
        {
            XmlArchiveTest store;

            // save block

            std::stringstream	xml(std::stringstream::out);
            boost::archive::xml_oarchive archive(xml);

            archive & BOOST_SERIALIZATION_NVP(store);

            xml.flush();

            auto xml1 =  xml.str();

            store.Value(234);

            // load block
            
            std::stringstream	xml2;

            xml2 << xml1;

            boost::archive::xml_iarchive archive2(xml2);

            archive2 & BOOST_SERIALIZATION_NVP(store);

            Assert::AreEqual(4, store.Value(), L"4 != store.Value");
        }

    };
}

Call stack

>	ucrtbased.dll!issue_debug_notification(const wchar_t * const message) Line 28	C++	Non-user code. Symbols loaded.
 	ucrtbased.dll!__acrt_report_runtime_error(const wchar_t * message) Line 154	C++	Non-user code. Symbols loaded.
 	ucrtbased.dll!abort() Line 51	C++	Non-user code. Symbols loaded.
 	ucrtbased.dll!terminate() Line 59	C++	Non-user code. Symbols loaded.
 	vcruntime140d.dll!FindHandler(EHExceptionRecord * pExcept, EHRegistrationNode * pRN, _CONTEXT * pContext, void * pDC, const _s_FuncInfo * pFuncInfo, unsigned char recursive, int CatchDepth, EHRegistrationNode * pMarkerRN) Line 627	C++	Non-user code. Symbols loaded.
 	vcruntime140d.dll!__InternalCxxFrameHandler(EHExceptionRecord * pExcept, EHRegistrationNode * pRN, _CONTEXT * pContext, void * pDC, const _s_FuncInfo * pFuncInfo, int CatchDepth, EHRegistrationNode * pMarkerRN, unsigned char recursive) Line 347	C++	Non-user code. Symbols loaded.
 	vcruntime140d.dll!__CxxFrameHandler(EHExceptionRecord * pExcept, EHRegistrationNode * pRN, void * pContext, void * pDC) Line 219	C++	Non-user code. Symbols loaded.
 	ntdll.dll!ExecuteHandler2@20()	Unknown	Non-user code. Symbols loaded.
 	ntdll.dll!ExecuteHandler@20()	Unknown	Non-user code. Symbols loaded.
 	ntdll.dll!_KiUserExceptionDispatcher@8()	Unknown	Non-user code. Symbols loaded.
 	KernelBase.dll!_RaiseException@16()	Unknown	Non-user code. Symbols loaded.
 	vcruntime140d.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 136	C++	Non-user code. Symbols loaded.
 	boost_serialization-vc141-mt-gd-x32-1_66.dll!0fe82f45()	Unknown	No symbols loaded.
 	[Frames below may be incorrect and/or missing, no symbols loaded for boost_serialization-vc141-mt-gd-x32-1_66.dll]		Annotated Frame
 	boost_serialization-vc141-mt-gd-x32-1_66.dll!0fec45ad()	Unknown	No symbols loaded.
 	boost_serialization-vc141-mt-gd-x32-1_66.dll!0fec72fc()	Unknown	No symbols loaded.
 	boost_serialization-vc141-mt-gd-x32-1_66.dll!0fec7d33()	Unknown	No symbols loaded.
 	UnitTestsUtilityLib.dll!boost::archive::xml_iarchive::~xml_iarchive() Line 129	C++	Symbols loaded.
 	UnitTestsUtilityLib.dll!UtilityLibTest::UnitTest1::XmlArchive_SaveLoad() Line 72	C++	Symbols loaded.

Change History (4)

comment:1 by anonymous, 5 years ago

I am having the same problem. I am loading a polymorphic object from an xml archive like this:

std::ifstream file(filename);
boost::archive::xml_iarchive iarchive(file);
Preferences * ptr;
iarchive >> boost::serialization::make_nvp("preferences", ptr);
return std::unique_ptr<Preferences>(ptr);

and it crashes after successfully reading the object.

It works with Boost 1.65. I am using GCC 6.4 on NixOS.

comment:2 by steto84@…, 5 years ago

seems that the problem is due to the following portion of code in basic_xml_grammar.ipp:

if(is.fail()){
            boost::serialization::throw_exception(
                boost::archive::archive_exception(
                    archive_exception::input_stream_error,
                    std::strerror(errno)
                )
            );
        }

reverting the file to the previous version seems to solve the problem:

 if(is.fail()){
            return false;
        }

comment:3 by Frédéric Devernay <frederic.devernay@…>, 5 years ago

probably a duplicate of #13400

comment:4 by Frédéric Devernay <frederic.devernay@…>, 5 years ago

ok, the problem seems to be that the end tag </boost_serialization> is missing.

try to apply the suggestion from http://boost.2283326.n4.nabble.com/the-boost-xml-serialization-to-a-stringstream-does-not-have-an-end-tag-td2580772.html

enclose the xml_oarchive in its own scope, so that its destructor is called before calling xml.str();

maybe boost could be more tolerant in this case, and not choke if the end tag is missing?

Note: See TracTickets for help on using tickets.