I have a serious regression in boost 1.42 serialisation.
Now getting a unregistered class, exception, on Suse linux
using gcc 4.2.1. This test passes on boost 1.39/1.40.
There are 3 files involved to recreate the crash:
included below:
Main.cpp
BaseHolder.hpp
BaseHolder.cpp
The file BaseHolder.hpp/cpp defines 3 classes
Base
Derived
BaseHolder
Here is what I found:
1/ If all the functionality is put in one file.
i.e Main.cpp then _no_ crash
2/ If all 3 files are compiled together then
_no_ crash
3/ However if BaseHolder is added to static library
and linked with Main.cpp
then we get the _crash_ ( only in 1.42 )
Also getting a spurious warning message:
Again this warning only appears in 1.42
/var/tmp/ma0/boost/boost_1_42_0/boost/mpl/print.hpp: In instantiation of ?boost::mpl::print<boost::serialization::BOOST_SERIALIZATION_STATIC_WARNING_LINE<98> >?:
/var/tmp/ma0/boost/boost_1_42_0/boost/serialization/static_warning.hpp:92: instantiated from ?boost::serialization::static_warning_test<false, 98>?
/var/tmp/ma0/boost/boost_1_42_0/boost/archive/detail/check.hpp:98: instantiated from ?void boost::archive::detail::check_object_tracking() [with T = Derived]?
/var/tmp/ma0/boost/boost_1_42_0/boost/archive/detail/oserializer.hpp:313: instantiated from ?static void boost::archive::detail::save_non_pointer_type<Archive>::invoke(Archive&, T&) [with T = Derived, Archive = boost::archive::text_oarchive]?
/var/tmp/ma0/boost/boost_1_42_0/boost/archive/detail/oserializer.hpp:525: instantiated from ?void boost::archive::save(Archive&, T&) [with Archive = boost::archive::text_oarchive, T = Derived]?
/var/tmp/ma0/boost/boost_1_42_0/boost/archive/detail/common_oarchive.hpp:69: instantiated from ?void boost::archive::detail::common_oarchive<Archive>::save_override(T&, int) [with T = Derived, Archive = boost::archive::text_oarchive]?
/var/tmp/ma0/boost/boost_1_42_0/boost/archive/basic_text_oarchive.hpp:80: instantiated from ?void boost::archive::basic_text_oarchive<Archive>::save_override(T&, int) [with T = Derived, Archive = boost::archive::text_oarchive]?
/var/tmp/ma0/boost/boost_1_42_0/boost/archive/detail/interface_oarchive.hpp:64: instantiated from ?Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(T&) [with T = Derived, Archive = boost::archive::text_oarchive]?
/var/tmp/ma0/clientRoot/workspace/MyProject/SCRATCH/src/Main.cpp:16: instantiated from here
/var/tmp/ma0/boost/boost_1_42_0/boost/mpl/print.hpp:55: warning: comparison between signed and unsigned integer expressions
gcc.archive bin/gcc-4.2.1/debug/link-static/libnodeattr.a
gcc.link bin/gcc-4.2.1/debug/test
Here are the 3 files:
// =========== file Main.cpp ============================
#include <iostream>
#include <fstream>
#include "BaseHolder.hpp"
using namespace std;
int main()
{
std::string fileName = "test.txt";
{ // If this scope is commented out, crash goes away ???
Derived saved("varname");
{
std::ofstream ofs( fileName.c_str() );
boost::archive::text_oarchive oa( ofs );
oa << saved;
}
Derived restored;
{
std::ifstream ifs( fileName.c_str() );
boost::archive::text_iarchive ia( ifs );
ia >> restored;
}
assert(saved == restored );
std::remove(fileName.c_str());
}
{
BaseHolder saved(Derived("varname"));
{
std::ofstream ofs( fileName.c_str() );
boost::archive::text_oarchive oa( ofs );
oa << saved;
}
BaseHolder restored;
{
std::ifstream ifs( fileName.c_str() );
boost::archive::text_iarchive ia( ifs );
ia >> restored;
}
assert(saved == restored);
std::remove(fileName.c_str());
}
cout << "Test passed \n";
}
//=================== file BaseHolder.hpp =============
#ifndef BASEHOLDER_HPP_
#define BASEHOLDER_HPP_
// defines classes:
// Base
// Derived
// BaseHolder
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/assume_abstract.hpp>
class Base {
public:
Base();
virtual ~Base();
virtual bool compare(Base*) const = 0;
virtual std::string name() const = 0;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &, const unsigned int){}
};
class Derived : public Base {
public:
Derived(const std::string& n) : name_(n) {}
Derived() {}
bool operator==(const Derived& rhs) const;
virtual std::string name() const { return name_;}
virtual bool compare(Base*) const;
private:
std::string name_;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int) {
ar & boost::serialization::base_object<Base>(*this);
ar & name_;
}
};
class BaseHolder {
public:
BaseHolder( const Derived& );
BaseHolder();
~BaseHolder();
std::string name() const
{ return basePtr_->name();}
bool operator==(const BaseHolder& rhs) const
{ return basePtr_->compare(rhs.basePtr_); }
private:
Base* basePtr_;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned){
ar & basePtr_;
}
};
#endif
//============= File BaseHolder.cpp =========
// implements class:
// Base
// Derived
// BaseHolder
#include <assert.h>
#include <sstream>
#include <boost/serialization/export.hpp>
#include "BaseHolder.hpp"
using namespace std;
// class Base
Base::Base() {}
Base::~Base() {}
// class derived
bool Derived::compare(Base* rb) const
{
Derived* rhs = dynamic_cast<Derived*>(rb);
if(!rhs) return false;
return operator==(*rhs);
}
bool Derived::operator==(const Derived& rhs) const
{
if (name_ != rhs.name_) {
return false;
}
return true;
}
BOOST_CLASS_EXPORT(Derived);
// class BaseHolder
BaseHolder::BaseHolder() : basePtr_(NULL) {}
BaseHolder::BaseHolder( const Derived& r)
: basePtr_(new Derived(r)) {}
BaseHolder::~BaseHolder() { delete basePtr_;}
Best regards,
Ta,
Avi