[Boost-bugs] [Boost C++ Libraries] #6856: Critical problem with serialization and class versioning

Subject: [Boost-bugs] [Boost C++ Libraries] #6856: Critical problem with serialization and class versioning
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2012-05-02 15:07:59


#6856: Critical problem with serialization and class versioning
---------------------------------+------------------------------------------
 Reporter: harris.pc@… | Owner: ramey
     Type: Bugs | Status: new
Milestone: To Be Determined | Component: serialization
  Version: Boost 1.49.0 | Severity: Problem
 Keywords: |
---------------------------------+------------------------------------------
 I am investigating strange error "input stream error" messages that I've
 been getting for a while when loading XML archives,
 and it turns out that boost::serialization is no longer enforcing strictly
 incrementing versioning numbers.

 Specifically the patch:
 https://github.com/ryppl/boost-
 svn/commit/66e85ade721a82bbc2e082749d6af2eefcb63dcb#boost/archive/detail
 Which has the comment:
 {{{
 + // note: we now comment this out. Before we permited archive
 + // version # to be very large. Now we don't. To permit
 + // readers of these old archives, we have to suppress this
 + // code. Perhaps in the future we might re-enable it but
 + // permit its suppression with a runtime switch.
 }}}


 I checked the documentation, and it is still assuming that class versions
 always increment, and it is implied (to me) that if a class version in an
 archive is larger than the BOOST_CLASS_VERSION() in the source, then it
 will not load (and checking the code, looks like it should throw a
 unsupported_class_version error).


 This is a critical problem, and is now my likely candidate for the reason
 why sometimes my programs crash when loading binary archives that are
 written by a newer version of my program.

 Basically, it NEVER checks if we are loading an archive that is newer than
 what the program is supported.  Thus, it will assume that it is reading
 the correct-versioned archive and serialize the wrong data in the wrong
 order.


 I wrote a small program to demonstrate the problem, most of the code was
 copied from the "bus" example in the documentation.

 The Makefile compiles 4 different versions:  xml and binary variants, each
 that write either version=0, version=1 classes.

 It is a program that loads an archive file (if the file can be opened),
 and then writes an archive file.

 The class written is a simple class with two integer variables.

 In version=0, it writes var1.

 In version=1, it writes var2, and then var1.


 This is what it looks like when you run the programs:


 {{{
 $ ./test_version_binary_0
 Could not open file to read: bus_route.binary
 Saved, var1=1
 ------- so a binary archive is written to disk, version=0
 $ ./test_version_binary_1
 Restored, var1=1 var2=2
 Saved, var1=1 var2=2
 ------- archive was loaded correctly, and then written back to disk, now
 version=1
 ------- now lets try and run the version=0 program
 $ ./test_version_binary_0
 Restored, var1=2
 FAIL! var1 should always be 1
 $
 ------- archive was loaded, apparently without error, but inspecting the
 data reveals that var1 was loaded with var2's value.
 }}}



 For the XML archive, we fortunately catch the problem, but only because it
 was expecting a different set of xml-tags:

 {{{
 $ ./test_version_xml_0
 Could not open file to read: bus_route.xml
 Saved, var1=1
 $ ./test_version_xml_1
 Restored, var1=1 var2=2
 Saved, var1=1 var2=2
 $ ./test_version_xml_0
 terminate called after throwing an instance of
 'boost::archive::xml_archive_exception'
 Â  what():  XML start/end tag mismatch - var1
 Aborted
 $
 }}}



 It seems to me that there are three solutions to this situation:

 1) ignore problem.  allow boost-based software to incorrectly load binary
 archives.

 2) change the documentation, tell users that they will need to manually
 test the version passed to void serialize(Archive,int) methods, and throw
 exceptions themselves if required.
 That will also mean upgrading all of the existing software and adding a
 test into every single serialize() function/method in existing production
 code.

 3) turn back on the version check that was turned off in the above patch.

 This is what it looks like when I change the #if 0 to #if 1


 {{{
 $ ./test_version_binary_0
 terminate called after throwing an instance of
 'boost::archive::archive_exception'
 Â  what():  class version 9bus_route
 Aborted
 }}}


 And that's what I was expecting it to do.

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/6856>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:09 UTC