Opened 10 years ago

#6856 new Bugs

Critical problem with serialization and class versioning

Reported by: harris.pc@… Owned by: Robert Ramey
Milestone: To Be Determined Component: serialization
Version: Boost 1.49.0 Severity: Problem
Keywords: Cc:

Description

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.

Attachments (2)

test_version.tar.gz (1.5 KB ) - added by harris.pc@… 10 years ago.
test source code
patch (678 bytes ) - added by harris.pc@… 10 years ago.
example patch against boost-trunk (via git repo mirror)

Download all attachments as: .zip

Change History (2)

by harris.pc@…, 10 years ago

Attachment: test_version.tar.gz added

test source code

by harris.pc@…, 10 years ago

Attachment: patch added

example patch against boost-trunk (via git repo mirror)

Note: See TracTickets for help on using tickets.