[Boost.Serialization] St8bad_cast during serialization
Hi, This would be my first post here. Needless to say I'm relatively a newbie when it comes to using Boost. I've recently decided to look into using Boost to ease some tasks in my future programming projects. I've stumbled upon Boost.Serialization and was amazed at the ease and power it provides. I've decided to use this to replace a hand-wrapped serialization library I created for a project I'm involved with since I foresee in the future more difficult serialization tasks that my library wouldn't be able to handle. So far so good, but during replacing my code with Boost.Serialization and going through various static asserts I've come to a obstacle I cannot figure out. My application saves message classes derived from a Message base class (it has a virtual deconstructor) and sends this serialized data over a UNIX socket for IPC between interconnected processes. The sending side seems to work fine as can be seen from the debugging output below: In base/module.cpp line 111 function SendMessage : [ 22 serialization::archive 3 4 core 10 LogMessage -1209954316 1 18 Sadrok::LogMessage 1 0 0 0 1168098092 55 Loaded module log from file modules/liblog.so pid 14250 ] However on the receiving side I have this: ia & BOOST_SERIALIZATION_NVP(msginfo.msg); which ends up throwing an bad_cast exception Unhandled exception: St8bad_cast msginfo.msg is Message* I even tried loading into a LogMessage * with the same error. I have (in the logmessage header) BOOST_CLASS_EXPORT for the LogMessage (otherwise Boost would've thrown unregistered_class while saving). I can provide more information although I wouldn't know what else to post. Generally I'd like to know if anyone has any idea why I'm getting the bad_cast exception, where it gets thrown, or at least how to figure out where the problem exists so I can fix it. Thank you Sadrok sadrok.za@gmail.com Yahoo! IM: sadrok_za Jabber ID: sadrok@jabber.obsidian.co.za
A couple of observations: a) you might try using xml_?archives for debugging. The consume more space are are easier to interpret. b) Could it be that you are doing something like: ar << lm ; // pointer to LogMessage ... ar >> m; // pointer to Message If so - this would be a problem. If you want to load(de-serialize) through a base class pointer, you have to save(serialize) also through a base class pointer. If this doesn't help, make a small test which just serializes and de-serializes and we can take a look at it. Robert Ramey sadrok wrote:
My application saves message classes derived from a Message base class (it has a virtual deconstructor) and sends this serialized data over a UNIX socket for IPC between interconnected processes. The sending side seems to work fine as can be seen from the debugging output below:
In base/module.cpp line 111 function SendMessage : [ 22 serialization::archive 3 4 core 10 LogMessage -1209954316 1 18 Sadrok::LogMessage 1 0 0 0 1168098092 55 Loaded module log from file modules/liblog.so pid 14250 ]
However on the receiving side I have this: ia & BOOST_SERIALIZATION_NVP(msginfo.msg); which ends up throwing an bad_cast exception Unhandled exception: St8bad_cast
msginfo.msg is Message* I even tried loading into a LogMessage * with the same error.
I have (in the logmessage header) BOOST_CLASS_EXPORT for the LogMessage (otherwise Boost would've thrown unregistered_class while saving).
Thanks for replying.
On 1/7/07, Robert Ramey
A couple of observations:
a) you might try using xml_?archives for debugging. The consume more space are are easier to interpret.
I've used xml_?archives now. The output looks satisfactory.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
b) Could it be that you are doing something like:
ar << lm ; // pointer to LogMessage ... ar >> m; // pointer to Message
I'm saving and loading using a pointer to Message.
If this doesn't help, make a small test which just serializes and de-serializes and we can take a look at it.
I did a small test loading the resultant XML from a file. It uses code copy & pasted from the program. The test works perfectly. I would expect that if I did something obviously wrong I would've gotten one of boost's exceptions (like unregistered_class) and I could fix my error. I however don't know why bad_cast gets thrown. For now I'll have to rip apart this program and try to reconstruct it piece by piece in a test program until the error pops up again.
Robert Ramey
sadrok wrote:
My application saves message classes derived from a Message base class (it has a virtual deconstructor) and sends this serialized data over a UNIX socket for IPC between interconnected processes.
-- sadrok@gmail.com Yahoo! IM: sadrok_za Jabber ID: sadrok@jabber.obsidian.co.za
sadrok wrote:
I notice that the XML is not completed, but this doesn't seem to be a problem.
This is usually caused by closing the output stream before the archive destructor is called. Its the archive destructor which finishes up the the xml in the archive. Robert Ramey
Thank you.
I've realized that after reading through some examples and tests.
Wrapping the archive instance inside its own scope fixed that.
I believe I have found the source of my problem. My program is
basically dynamically loading another module and forking a process to
run that module in. Both the parent module and the client module had
the LogMessage class exported by boost. Since the client inherited the
memory space of the parent this caused the troubles. Now I will just
figure out an elegant way to make sure that the LogMessage gets
exported only once.
Thanks for the help.
On 1/7/07, Robert Ramey
sadrok wrote:
I notice that the XML is not completed, but this doesn't seem to be a problem.
This is usually caused by closing the output stream before the archive destructor is called. Its the archive destructor which finishes up the the xml in the archive.
Robert Ramey
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
-- sadrok@gmail.com Yahoo! IM: sadrok_za Jabber ID: sadrok@jabber.obsidian.co.za
sadrok wrote: skip "export" and just use "register" to register your derived types. Robert Ramey
I believe I have found the source of my problem. My program is basically dynamically loading another module and forking a process to run that module in. Both the parent module and the client module had the LogMessage class exported by boost. Since the client inherited the memory space of the parent this caused the troubles. Now I will just figure out an elegant way to make sure that the LogMessage gets exported only once.
On 1/7/07, Robert Ramey
Robert wrote:
skip "export" and just use "register" to register your derived types.
I've done that now for LogMessage only (as a special case), registering only if I know its a LogMessage from its 'type' member. Other derived classes are exported using the macro. Thanks for the help.
sadrok wrote:
I believe I have found the source of my problem. My program is basically dynamically loading another module and forking a process to run that module in. Both the parent module and the client module had the LogMessage class exported by boost. Since the client inherited the memory space of the parent this caused the troubles. Now I will just figure out an elegant way to make sure that the LogMessage gets exported only once.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
-- sadrok@gmail.com Yahoo! IM: sadrok_za Jabber ID: sadrok@jabber.obsidian.co.za
Robert Ramey wrote:
sadrok wrote:
I notice that the XML is not completed, but this doesn't seem to be a problem.
This is usually caused by closing the output stream before the archive destructor is called. Its the archive destructor which finishes up the the xml in the archive.
Is there an explicit way to flush the archive before reaching its destructor? Presumably writing output to a stream can cause an exception to be thrown, and we would want to be able to handle such errors rather than hitting terminate(). -- James
James Dennett wrote: There isn't. I'm not sure there should be. Its only needed for xml archives but adding it would require that it be put in all the other archives as a no-op. Also "flush" suggests that one could continue using the archive after it was "flushed" like a stream. This would not be case as the function of "flush" would be to finish off the xml data structure. Ideally what I would like to do is throw an exception in the archive destructor if the stream is still open - but that's not a good idea.
Is there an explicit way to flush the archive before reaching its destructor? Presumably writing output to a stream can cause an exception to be thrown, and we would want to be able to handle such errors rather than hitting terminate().
-- James
Robert Ramey wrote:
James Dennett wrote:
Is there an explicit way to flush the archive before reaching its destructor? Presumably writing output to a stream can cause an exception to be thrown, and we would want to be able to handle such errors rather than hitting terminate().
-- James
There isn't. I'm not sure there should be. It's only needed for xml archives but adding it would require that it be put in all the other archives as a no-op.
Indeed; that's often the cost of polymorphically supporting a wider range of behaviors.
Also "flush" suggests that one could continue using the archive after it was "flushed" like a stream. This would not be case as the function of "flush" would be to finish off the xml data structure.
Fair comment; flush wasn't a suggested name. A better name would be "close".
Ideally what I would like to do is throw an exception in the archive destructor if the stream is still open - but that's not a good idea.
Right, that's the crux of the issues; destructors that do things that can throw are highly problematic, which is an argument for allowing everything that might throw to be moved out of a destructor. Most destructors really ought just to destroy things and release resources; if a destructor does something that can fail, there ought to be a way to try to do that from a named function so that the error can be handled as well as possible. -- James
participants (3)
-
James Dennett
-
Robert Ramey
-
sadrok