Boost logo

Boost Users :

Subject: [Boost-users] boost serialisation: portable binary format cant cope with -1
From: Avi Bahra (avibahra_at_[hidden])
Date: 2010-03-09 12:33:16


I have a strange bug where on the AIX platform I get:
boost::archive exception for TimeStruct : integer cannot be represented
for boost version 1.40

on restoring a class(TimeStruct) that has a integer
data member of value of -1.
 Its seems strange that the exception is
_only_ raised when restoring the class, and not saving
Its missing some symmetry somewhere ?

Here is the stack trace:

//boost::serialization::throw_exception<portable_binary_iarchive_exception>,
//portable_binary_iarchive::load_impl,
//portable_binary_iarchive::load<int>,
//boost::archive::load_access::load_primitive<portable_binary_iarchive,int>,
//boost::archive::detail::load_non_pointer_type<portable_binary_iarchive,int>::load_primitive::invoke,
//boost::archive::detail::load_non_pointer_type<portable_binary_iarchive,int>::invoke,
//boost::archive::load<portable_binary_iarchive,int>,
//boost::archive::detail::common_iarchive<portable_binary_iarchive>::load_override<int>,
//portable_binary_iarchive::load_override<int>,
//boost::archive::detail::interface_iarchive<portable_binary_iarchive>::operator
>><int>,
//boost::archive::detail::interface_iarchive<portable_binary_iarchive>::operator
&<int>,
//TimeStruct::serialize<portable_binary_iarchive>,
// .....

This is raised in:

void
portable_binary_iarchive::load_impl(boost::intmax_t & l, char maxsize){
     char size;
     l = 0;
     this->primitive_base_t::load(size);

     if(0 == size){
         return;
     }

     bool negative = (size < 0);
     if(negative)
         size = -size;

     if(size > maxsize)
         boost::serialization::throw_exception(
             portable_binary_iarchive_exception()
         );
     .....

The exception is raised because size=255 and maxsize=4 ?

Here is the example which produces the exception:
Please note that you will have to dig out and
compile the portable binary archives out of the
boost serialisation examples dirs.

//================ Main.cpp =========================
// This example demonstrates a possible bug in
// portable binary format on AIX when serialising -1
// that is specific only to the AIX compiler/platform
// (i.e HPUX/Acc and linux/gcc run without any problems)
// However on AIX on the restore I get:
// boost::archive exception for TimeStruct : integer cannot be
represented
//
// This test consists of 1 files
// 1/ Main.cpp
//
#include <sstream>
#include <ostream>
#include <iostream>
#include <fstream>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include "portable_binary_oarchive.hpp"
#include "portable_binary_iarchive.hpp"
#include <boost/serialization/serialization.hpp>

using namespace std;

class TimeStruct {
public:
    TimeStruct() : hour_(-1), minute_(-1) {}
    TimeStruct(int hour, int min) : hour_(hour), minute_(min) {}

    bool operator==(const TimeStruct& rhs) const { return ((hour_ ==
rhs.hour_) && (minute_ == rhs.minute_));}
    bool operator!=(const TimeStruct& rhs) const { return !operator==(rhs);}

    int hour() const { return hour_;}
    int minute() const { return minute_;}
    bool isNULL() const { return (hour_ == -1) || (minute_ == -1); }

     // returns struct in the format hh:mm
     std::string toString() const {
         std::stringstream ss;
         if (hour_ == -1) ss << hour_;
         else if (hour_ < 10) ss << "0" << hour_;
         else ss << hour_;

         ss << ":";
         if (minute_ == -1) ss << minute_;
         else if (minute_ < 10) ss << "0" << minute_;
         else ss << minute_;
         return ss.str();
     }
private:
    int hour_;
    int minute_;

    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int /*version*/) {
        ar & hour_;
        ar & minute_;
    }
};

bool compare(const TimeStruct& lhs, const TimeStruct& rhs)
{
    if (lhs.isNULL() && rhs.isNULL()) return true;
    if (lhs.isNULL() && !rhs.isNULL()) return false;
    if (!lhs.isNULL() && rhs.isNULL()) return false;
    if (lhs.hour() != rhs.hour()) return false;
    if (lhs.minute() != rhs.minute()) return false;
    return true;
};

static void save(const std::string& fileName, const TimeStruct& ts, bool
textArchive);
static void restore(const std::string& fileName, TimeStruct& ts, bool
textArchive);

int main()
{
    {
        TimeStruct saved;
        save("fred.txt",saved,true);
        TimeStruct restored;
        restore("fred.txt",restored,true);
        assert(saved == restored);
    }
    {
        TimeStruct saved;
        save("fred.txt",saved,false);
        TimeStruct restored;
        restore("fred.txt",restored,false);
        assert(saved == restored);
    }
    return 0;
}

void save(const std::string& fileName, const TimeStruct& ts, bool
textArchive)
{
    if ( textArchive ) std::cout << "Text archive Saving " << ts.toString();
    else std::cout << "portable binary archive Saving " <<
ts.toString();
      try {
        if (textArchive) {
            std::ofstream ofs( "fred.txt" );
            boost::archive::text_oarchive ar( ofs );
            ar << ts;
        }
        else {
            std::ofstream ofs( fileName.c_str(), ios::binary );
            portable_binary_oarchive ar(ofs);
            ar << ts;
        }

        std::cout << " OK \n";
    }
    catch (const boost::archive::archive_exception& ae) {
        std::cout << " save " << fileName
        << " failed. boost::archive exception for TimeStruct "
        << ": " << ae.what() << std::endl;
    }
}

void restore(const std::string& fileName, TimeStruct& restored, bool
textArchive)
{
    if ( textArchive ) std::cout << "Text archive Restoring ";
    else std::cout << "portable binary archive Restoring " ;

    try {
        if ( textArchive ) {
            std::ifstream ifs( fileName.c_str() );
            boost::archive::text_iarchive ar( ifs );
            ar >> restored;
        }
        else {
            std::ifstream ifs( fileName.c_str(), ios::binary );
            portable_binary_iarchive ar( ifs );
            ar >> restored;
        }

        std::cout << restored.toString() << " OK \n";
    }
    catch ( const boost::archive::archive_exception& ae ) {
        std::cout << " restore " << fileName
        << " failed. boost::archive exception for TimeStruct "
        << ": " << ae.what() << std::endl;
     }
}

  Best regards,
Ta,
   Avi



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net