Re: [boost] [serialization] basic_text_iprimitive destructor throws

Here's a two-line patch (not counting the comment). This patch simply ignores any ios_base::failure excpetions from is.sync(). There are certainly other possibilities, but I don't see any good reason to prefer, e.g., checking the result of std::uncaught_exception() first or to broaden the class of caught exceptions. John P.S. I've changed the subject to adhere to conventions. salmonj@drdblogin6.en.desres$ diff -u boost/archive/impl/basic_text_iprimitive.ipp.orig boost/archive/impl/basic_text_iprimitive.ipp --- boost/archive/impl/basic_text_iprimitive.ipp.orig 2008-11-09 16:32:30.003405292 -0500 +++ boost/archive/impl/basic_text_iprimitive.ipp 2008-11-09 16:38:51.755281718 -0500 @@ -147,7 +147,17 @@ template<class IStream> BOOST_ARCHIVE_OR_WARCHIVE_DECL(BOOST_PP_EMPTY()) basic_text_iprimitive<IStream>::~basic_text_iprimitive(){ - is.sync(); + try{ + is.sync(); + }catch(std::ios_base::failure& e){ + // is.sync might throw ios_base::failure if an error + // occurs and 'is' has the badbit exception + // mask set. Should this exception be allowed to "leak out" + // of this destructor: + // a) never? + // b) only if std::uncaught_exception() is false? + // c) under some other set of circumstances? + } } } // namespace archive salmonj@drdblogin6.en.desres$ On Tue, Nov 4, 2008 at 4:17 PM, John Salmon <john@thesalmons.org> wrote:
I tried turning on exceptions on the input stream that I use for a text_iarchive, hoping to catch user-level errors such as an attempt to treat a non-archive file as an archive. It seems that when exceptions are enabled on the underlying stream, the basic_text_iprimitive destructor throws a second(?) basic_ios::failure exception, during stack unwinding, which lands me unhappily in the terminate handler.
Can the basic_text_iprimitive destructor be protected against accidentally throwing?
Here's an demonstration. This is on a Linux system with gcc/4.1.2.
John Salmon
salmonj@drdblogin6.en.desres$ cat ser.cpp #include <boost/archive/text_iarchive.hpp> #include <boost/serialization/serialization.hpp> #include <stdexcept>
#include <fstream>
struct Foo{ int i, j; private: friend class boost::serialization::access; template <class Archive> void serialize(Archive & ar, const unsigned int version) { ar & i & j; } };
int main(){ Foo foo; std::ifstream ifs("/dev/null"); ifs.exceptions(std::istream::failbit | std::istream::badbit);
try{ boost::archive::text_iarchive tia(ifs); tia >> foo; }catch(std::ios_base::failure &e){ std::cerr << "Caught std::ios_base::failure. What: " << e.what() << "\n"; }catch(std::exception &e){ std::cerr << "Caught exception. What: " << e.what() << "\n"; }
return 0; }
salmonj@drdblogin6.en.desres$ xmk g++ -I/proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/include -g -L/proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/lib -Wl,-rpath,/proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/lib ser.cpp -lboost_serialization -o ser salmonj@drdblogin6.en.desres$ ser terminate called after throwing an instance of 'std::ios_base::failure' what(): basic_ios::clear Aborted (core dumped) salmonj@drdblogin6.en.desres$ gdb -c drdblogin6.en.desres.deshaw.com-6718.core ser GNU gdb 6.8 Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-unknown-linux-gnu"... Reading symbols from /proj/desrad-c/root/Linux/x86_64/boost/1_37_0-13/Release/lib/libboost_serialization.so...done. Loaded symbols for /proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/lib/libboost_serialization.so Reading symbols from /proj/desrad-c/root/Linux/x86_64/gcc/4.1.2-10/lib64/libstdc++.so.6...done. Loaded symbols for /proj/desres/root/Linux/x86_64/gcc/4.1.2-10/lib64/libstdc++.so.6 Reading symbols from /lib64/tls/libm.so.6...done. Loaded symbols for /lib64/tls/libm.so.6 Reading symbols from /proj/desrad-c/root/Linux/x86_64/gcc/4.1.2-10/lib64/libgcc_s.so.1...done. Loaded symbols for /proj/desres/root/Linux/x86_64/gcc/4.1.2-10/lib64/libgcc_s.so.1 Reading symbols from /lib64/tls/libc.so.6...done. Loaded symbols for /lib64/tls/libc.so.6 Reading symbols from /lib64/ld-linux-x86-64.so.2...done. Loaded symbols for /lib64/ld-linux-x86-64.so.2 Core was generated by `ser'. Program terminated with signal 6, Aborted. [New process 6718] #0 0x0000003f72a2e25d in raise () from /lib64/tls/libc.so.6 (gdb) where #0 0x0000003f72a2e25d in raise () from /lib64/tls/libc.so.6 #1 0x0000003f72a2fa5e in abort () from /lib64/tls/libc.so.6 #2 0x00002b5ab82f5f84 in __gnu_cxx::__verbose_terminate_handler () at /state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/libstdc++-v3/libsupc++/vterminate.cc:97 #3 0x00002b5ab82f4106 in __cxxabiv1::__terminate (handler=0x1a3e) at /state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/libstdc++-v3/libsupc++/eh_terminate.cc:43 #4 0x00002b5ab82f350b in __cxa_call_terminate (ue_header=0x50b730) at /state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/libstdc++-v3/libsupc++/eh_call.cc:60 #5 0x00002b5ab82f3fa7 in __gxx_personality_v0 ( version=<value optimized out>, actions=6, exception_class=<value optimized out>, ue_header=0x50b730, context=0x7ffff29e5610) at /state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/libstdc++-v3/libsupc++/eh_personality.cc:637 #6 0x00002b5ab846a068 in _Unwind_RaiseException_Phase2 (exc=0x50b730, context=0x7ffff29e5610) at /state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/gcc/unwind.inc:66 #7 0x00002b5ab846a2db in _Unwind_Resume (exc=0x50b730) at /state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/gcc/unwind.inc:234 #8 0x00002b5ab80fd790 in boost::archive::basic_text_iprimitive<std::istream>::~basic_text_iprimitive () from /proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/lib/libboost_serialization.so #9 0x00002b5ab8109e0c in boost::archive::text_iarchive_impl<boost::archive::text_iarchive>::text_iarchive_impl () from /proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/lib/libboost_serialization.so #10 0x00000000004045ab in text_iarchive (this=0x7ffff29e5ae0, is=@0x7ffff29e58d0, flags=0) at /proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/include/boost/archive/text_iarchive.hpp:110 #11 0x0000000000402c84 in main () at ser.cpp:24 (gdb) quit salmonj@drdblogin6.en.desres$

When I looked into this, I was surprised that stream threw exception. It seems that it depends on which standard library is being used so I don't think that std::failure exists in all standard libraries. I would guess that one would want to ignore all exceptions at this poing. Robert Ramey John Salmon wrote:
Here's a two-line patch (not counting the comment). This patch simply ignores any ios_base::failure excpetions from is.sync(). There are certainly other possibilities, but I don't see any good reason to prefer, e.g., checking the result of std::uncaught_exception() first or to broaden the class of caught exceptions.
John
P.S. I've changed the subject to adhere to conventions.
salmonj@drdblogin6.en.desres$ diff -u boost/archive/impl/basic_text_iprimitive.ipp.orig boost/archive/impl/basic_text_iprimitive.ipp --- boost/archive/impl/basic_text_iprimitive.ipp.orig 2008-11-09 16:32:30.003405292 -0500 +++ boost/archive/impl/basic_text_iprimitive.ipp 2008-11-09 16:38:51.755281718 -0500 @@ -147,7 +147,17 @@ template<class IStream> BOOST_ARCHIVE_OR_WARCHIVE_DECL(BOOST_PP_EMPTY()) basic_text_iprimitive<IStream>::~basic_text_iprimitive(){ - is.sync(); + try{ + is.sync(); + }catch(std::ios_base::failure& e){ + // is.sync might throw ios_base::failure if an error + // occurs and 'is' has the badbit exception + // mask set. Should this exception be allowed to "leak out" + // of this destructor: + // a) never? + // b) only if std::uncaught_exception() is false? + // c) under some other set of circumstances? + } }
} // namespace archive salmonj@drdblogin6.en.desres$
On Tue, Nov 4, 2008 at 4:17 PM, John Salmon <john@thesalmons.org> wrote:
I tried turning on exceptions on the input stream that I use for a text_iarchive, hoping to catch user-level errors such as an attempt to treat a non-archive file as an archive. It seems that when exceptions are enabled on the underlying stream, the basic_text_iprimitive destructor throws a second(?) basic_ios::failure exception, during stack unwinding, which lands me unhappily in the terminate handler.
Can the basic_text_iprimitive destructor be protected against accidentally throwing?
Here's an demonstration. This is on a Linux system with gcc/4.1.2.
John Salmon
salmonj@drdblogin6.en.desres$ cat ser.cpp #include <boost/archive/text_iarchive.hpp> #include <boost/serialization/serialization.hpp> #include <stdexcept>
#include <fstream>
struct Foo{ int i, j; private: friend class boost::serialization::access; template <class Archive> void serialize(Archive & ar, const unsigned int version) { ar & i & j; } };
int main(){ Foo foo; std::ifstream ifs("/dev/null"); ifs.exceptions(std::istream::failbit | std::istream::badbit);
try{ boost::archive::text_iarchive tia(ifs); tia >> foo; }catch(std::ios_base::failure &e){ std::cerr << "Caught std::ios_base::failure. What: " << e.what() << "\n"; }catch(std::exception &e){ std::cerr << "Caught exception. What: " << e.what() << "\n"; }
return 0; }
salmonj@drdblogin6.en.desres$ xmk g++ -I/proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/include -g -L/proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/lib -Wl,-rpath,/proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/lib ser.cpp -lboost_serialization -o ser salmonj@drdblogin6.en.desres$ ser terminate called after throwing an instance of 'std::ios_base::failure' what(): basic_ios::clear Aborted (core dumped) salmonj@drdblogin6.en.desres$ gdb -c drdblogin6.en.desres.deshaw.com-6718.core ser GNU gdb 6.8 Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-unknown-linux-gnu"... Reading symbols from /proj/desrad-c/root/Linux/x86_64/boost/1_37_0-13/Release/lib/libboost_serialization.so...done. Loaded symbols for /proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/lib/libboost_serialization.so Reading symbols from /proj/desrad-c/root/Linux/x86_64/gcc/4.1.2-10/lib64/libstdc++.so.6...done. Loaded symbols for /proj/desres/root/Linux/x86_64/gcc/4.1.2-10/lib64/libstdc++.so.6 Reading symbols from /lib64/tls/libm.so.6...done. Loaded symbols for /lib64/tls/libm.so.6 Reading symbols from /proj/desrad-c/root/Linux/x86_64/gcc/4.1.2-10/lib64/libgcc_s.so.1...done. Loaded symbols for /proj/desres/root/Linux/x86_64/gcc/4.1.2-10/lib64/libgcc_s.so.1 Reading symbols from /lib64/tls/libc.so.6...done. Loaded symbols for /lib64/tls/libc.so.6 Reading symbols from /lib64/ld-linux-x86-64.so.2...done. Loaded symbols for /lib64/ld-linux-x86-64.so.2 Core was generated by `ser'. Program terminated with signal 6, Aborted. [New process 6718] #0 0x0000003f72a2e25d in raise () from /lib64/tls/libc.so.6 (gdb) where #0 0x0000003f72a2e25d in raise () from /lib64/tls/libc.so.6 #1 0x0000003f72a2fa5e in abort () from /lib64/tls/libc.so.6 #2 0x00002b5ab82f5f84 in __gnu_cxx::__verbose_terminate_handler () at /state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/libstdc++-v3/libsupc++/vterminate.cc:97 #3 0x00002b5ab82f4106 in __cxxabiv1::__terminate (handler=0x1a3e) at
/state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/libstdc++-v3/libsupc++/eh_terminate.cc:43 #4 0x00002b5ab82f350b in __cxa_call_terminate (ue_header=0x50b730) at
/state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/libstdc++-v3/libsupc++/eh_call.cc:60 #5 0x00002b5ab82f3fa7 in __gxx_personality_v0 ( version=<value optimized out>, actions=6, exception_class=<value optimized out>, ue_header=0x50b730, context=0x7ffff29e5610) at
/state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/libstdc++-v3/libsupc++/eh_personality.cc:637 #6 0x00002b5ab846a068 in _Unwind_RaiseException_Phase2 (exc=0x50b730, context=0x7ffff29e5610) at /state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/gcc/unwind.inc:66 #7 0x00002b5ab846a2db in _Unwind_Resume (exc=0x50b730) at /state/partition1/tmp/tmpXcQw4O/gcc-4.1.2-10/gcc-4.1.2/gcc/unwind.inc:234 #8 0x00002b5ab80fd790 in boost::archive::basic_text_iprimitive<std::istream>::~basic_text_iprimitive () from /proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/lib/libboost_serialization.so #9 0x00002b5ab8109e0c in boost::archive::text_iarchive_impl<boost::archive::text_iarchive>::text_iarchive_impl () from /proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/lib/libboost_serialization.so #10 0x00000000004045ab in text_iarchive (this=0x7ffff29e5ae0, is=@0x7ffff29e58d0, flags=0) at /proj/desres/root/Linux/x86_64/boost/1_37_0-13/Release/include/boost/archive/text_iarchive.hpp:110 #11 0x0000000000402c84 in main () at ser.cpp:24 (gdb) quit salmonj@drdblogin6.en.desres$
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (2)
-
John Salmon
-
Robert Ramey