boost::serialization unregistered_class exceptions with DLL.
Re: unregistered_class exceptions are thrown when the derived class are in
an explicitly loaded DLL.
Hello,
In a nutshell, the problem that I have is that an "unregistered_class"
exception is thrown when the derived class is defined/declared in a DLL that
is explicitly loaded.
The problem as far as I can tell is that the derived class in dll and the
derived class in the framework are being "registered" in two different
instances (m_self->m_map.insert(eti); in "extended_type_info.cpp").
Exception is thrown when trying to serialize the foobar_derived_dll. It
looks for "foobar_derived_dll" in the wrong instance of the m_map defined in
the extened_type_info.cpp and then throws an exception.
Can anybody please help
The Application Structure is more or less as follows.
Common Framework Library Contains.
class foobar_base : public foobar_base
{
protected:
bool m_attr0;
public:
foobar_base() {}
template<class Archive>
void serialize(Archive & ar, const unsigned int /* file_version */){
std::cout << "serialize foobar_base\n";
ar & BOOST_SERIALIZATION_NVP(m_attr0);
}
}
class foobar_derived : public foobar_base
{
protected:
bool m_attr1;
public:
foobar_derived() {}
template<class Archive>
void serialize(Archive & ar, const unsigned int /* file_version */){
std::cout << "serialize foobar_derived_dll\n";
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(foobar_base);
ar & BOOST_SERIALIZATION_NVP(m_attr1);
}
}
BOOST_CLASS_EXPORT_GUID(foobar_derived, "foobar_derived")
Dynamic Link Library Contains (Includes Common Framework Library)
class foobar_derived_dll
{
protected:
bool m_attr2;
public:
foobar_derived_dll() {}
template<class Archive>
void serialize(Archive & ar, const unsigned int /* file_version */){
std::cout << "serialize foobar_derived_dll\n";
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(foobar_base);
ar & BOOST_SERIALIZATION_NVP(m_attr2);
}
}
BOOST_CLASS_EXPORT_GUID(foobar_derived_dll, "foobar_derived_dll")
Main Application (includes Common framework library & explictly lods Dynamic
Link Library)
class foo {
public:
std::list
This has been bugging me for a while but I never really found the time to really track it down. Perhaps you could do a little sleuthing while your there. I would expect that the problem due to the fact that foobar_base is "registered" twice - once when the app starts up and a second time when the derived class DLL is "registered" when the DLL is loaded. So I believe that the problem would not appear if foobar_base were in the DLL as well.
The reason that I've enforce the restriction that serialization code be instanticiated only once was that when It was permitted multiple times, the "unregister" code would sometimes remove the wrong instance. So that things would crash in an unpredictable and obscure way. Its still not clear to me the best way to handle this. I guess that the eti has to be "registered" along with a handle to its code module (executable, dll or shared library). So far I haven't spent any time on investigating this.
Thanks for a good example which illustrates the problem in a digestable manner.
Robert Ramey
"Arjuna Balasingham"
Dear Robert,
I have also been stymied by this bug, for me it is a show stopper because
our application is composed of many DLL's rather than a single executable.
If it would help you, I can provide a small VC8 project which demonstrates
the issue. I'm motivated to help you fix the problem as your library could
potentially be very useful in our work.
Could you please explain what you mean by registered twice? As I understand
it, the base and derived classes should be registered, is this what you
refer to or do you mean registered twice, the same class once in each
module?
Thanks for your help,
Terence
_____
From: boost-users-bounces@lists.boost.org
[mailto:boost-users-bounces@lists.boost.org] On Behalf Of Robert Ramey
Sent: Tuesday, June 13, 2006 1:23 PM
To: boost-users@lists.boost.org
Subject: Re: [Boost-users] boost::serialization
unregistered_classexceptionswith DLL.
This has been bugging me for a while but I never really found the time to
really track it down. Perhaps you could do a little sleuthing while your
there. I would expect that the problem due to the fact that foobar_base is
"registered" twice - once when the app starts up and a second time when the
derived class DLL is "registered" when the DLL is loaded. So I believe that
the problem would not appear if foobar_base were in the DLL as well.
The reason that I've enforce the restriction that serialization code be
instanticiated only once was that when It was permitted multiple times, the
"unregister" code would sometimes remove the wrong instance. So that things
would crash in an unpredictable and obscure way. Its still not clear to me
the best way to handle this. I guess that the eti has to be "registered"
along with a handle to its code module (executable, dll or shared library).
So far I haven't spent any time on investigating this.
Thanks for a good example which illustrates the problem in a digestable
manner.
Robert Ramey
"Arjuna Balasingham"
The problem is when one uses BOOST_CLASS_EXPORT
This creates a static object which is constructed at pre-execution time - before calling main. This static object adds itself to a global table which points to the functions to serialize/deserialize pointers to derived objects not mentioned by name. Thus the code to serialize/deserialise these objects is instantiated even though there may be no place in the program which does ar << "derived object"
So far - so good.
When a BOOST_CLASS_EXPORT is used in a DLL the static object is created which the DLL is loaded and destroyed when the DLL is unloaded. Upon construction/destruction, the pointer to the instanticiated code is added/deleted from this global table.
So far - so good.
In this case the DLL loads a derived class - which through the base_object syntax includes serialization/deserialization of the base class. In this case, the base class serialization is also in the main executable. So when the second instance (the DLL version) is loaded another instance of the base class code is added to the global table. This triggers and exception as we can't have to possible different instantiations of the same code. This create the possibility that the when the DLL is unloaded the table entry corresponding the the instantiation in the main program might be removed - thus leaving an reference to he code in the now removed DLL.
Short term solution.
Hmm - not sure. If ALL the base classes are in the DLL I don't think there should be a problem.
Long term solution.
The global table might include a handle to the code module which created the entry. This could be used to be sure that the correct entry is deleted as teh DLL is deleted. In windows there is a call to retrieve a handle to the current module - main, DLL etc. I don't know what the corresponding call is on a unix/cygwin/ etc environment. Any one is free to chime in here.
Robert Ramey
"Terence Wilson"
# ramey@rrsd.com / 2006-06-15 10:30:49 -0700:
The global table might include a handle to the code module which created the entry. This could be used to be sure that the correct entry is deleted as teh DLL is deleted. In windows there is a call to retrieve a handle to the current module - main, DLL etc. I don't know what the corresponding call is on a unix/cygwin/ etc environment. Any one is free to chime in here.
How about just reference counting the types? -- How many Vietnam vets does it take to screw in a light bulb? You don't know, man. You don't KNOW. Cause you weren't THERE. http://bash.org/?255991
Roman Neuhauser wrote:
# ramey@rrsd.com / 2006-06-15 10:30:49 -0700:
The global table might include a handle to the code module which created the entry. This could be used to be sure that the correct entry is deleted as teh DLL is deleted. In windows there is a call to retrieve a handle to the current module - main, DLL etc. I don't know what the corresponding call is on a unix/cygwin/ etc environment. Any one is free to chime in here.
How about just reference counting the types?
Not enough. DLLS can be unloaded in different order than they are loaded. What is needed is to include a handle of the module doing the registration. I can find the magic handle in windows - but I don't know how to do it in UNIX. Robert Ramey
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Robert Ramey Sent: Thursday, June 15, 2006 10:28 PM To: boost-users@lists.boost.org Subject: Re: [Boost- users]boost::serializationunregistered_classexceptionswith DLL.
Roman Neuhauser wrote:
# ramey@rrsd.com / 2006-06-15 10:30:49 -0700:
The global table might include a handle to the code module which created the entry. This could be used to be sure that the correct entry is deleted as teh DLL is deleted. In windows there is a call to retrieve a handle to the current module - main, DLL etc. I don't know what the corresponding call is on a unix/cygwin/ etc environment. Any one is free to chime in here.
How about just reference counting the types?
Not enough. DLLS can be unloaded in different order than they are loaded.
What is needed is to include a handle of the module doing the registration. I can find the magic handle in windows - but I don't know how to do it in UNIX.
Robert Ramey
Robert, I've used your serialization library for small projects and I like it a lot, however, the DLL class registration bug/oversight makes it all but impossible to use in a Windows project that separates implementation of classes across modules. We have several classes that have encapsulated bases implemented within a 'base' DLL, specializations of these classes are loaded at runtime on an as-needed basis. Your current design requires that *all* class registration occur within the base class module, in other words, the base DLL must have knowledge of all other DLL classes that derive from one or more of its base classes. This turns any good object-oriented design on its head and is not an option. Is there any chance of a fix in the near future? Thanks, Terence
I believe it is fixable in a general and definitive way. And I've slowly been gathering the information needed to address this for differenent operating systems. Also, I havn't been able to see a way to use bjam to run a test which dynamically loads/unloads separately built DLLS. I'm still thinking about this. Also, I don't have the time I used to for this stuff, so - short answer is that I wouldn't count on this being addressed anytime soon. Note that this isn't really a design feature of the library. Its just that the concept what DLLS which contain partial class implementations (with base impleentation somewhere else) was never considered. We tried to consider everything - but its not easy Robert Ramey Terence Wilson wrote:
-----Original Message----- Robert,
I've used your serialization library for small projects and I like it a lot, however, the DLL class registration bug/oversight makes it all but impossible to use in a Windows project that separates implementation of classes across modules. We have several classes that have encapsulated bases implemented within a 'base' DLL, specializations of these classes are loaded at runtime on an as-needed basis. Your current design requires that *all* class registration occur within the base class module, in other words, the base DLL must have knowledge of all other DLL classes that derive from one or more of its base classes. This turns any good object-oriented design on its head and is not an option.
Is there any chance of a fix in the near future?
Thanks,
Terence
Dear Robert, If there's anything I can do to help with Windows specific DLL issues let me know, I would be happy to help. I would take a stab at a Windows only fix but I fear it would take too long to climb the learning curve. Terence
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Robert Ramey Sent: Monday, June 19, 2006 2:47 PM To: boost-users@lists.boost.org Subject: Re: [Boost- users]boost::serializationunregistered_classexceptionswith DLL.
I believe it is fixable in a general and definitive way. And I've slowly been gathering the information needed to address this for differenent operating systems. Also, I havn't been able to see a way to use bjam to run a test which dynamically loads/unloads separately built DLLS. I'm still thinking about this. Also, I don't have the time I used to for this stuff, so - short answer is that I wouldn't count on this being addressed anytime soon.
Note that this isn't really a design feature of the library. Its just that the concept what DLLS which contain partial class implementations (with base impleentation somewhere else) was never considered. We tried to consider everything - but its not easy
Robert Ramey
Terence Wilson wrote:
-----Original Message----- Robert,
I've used your serialization library for small projects and I like it a lot, however, the DLL class registration bug/oversight makes it all but impossible to use in a Windows project that separates implementation of classes across modules. We have several classes that have encapsulated bases implemented within a 'base' DLL, specializations of these classes are loaded at runtime on an as-needed basis. Your current design requires that *all* class registration occur within the base class module, in other words, the base DLL must have knowledge of all other DLL classes that derive from one or more of its base classes. This turns any good object-oriented design on its head and is not an option.
Is there any chance of a fix in the near future?
Thanks,
Terence
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
"Robert Ramey"
I believe it is fixable in a general and definitive way. And I've slowly been gathering the information needed to address this for differenent operating systems. Also, I havn't been able to see a way to use bjam to run a test which dynamically loads/unloads separately built DLLS.
The Python tests do that. I suggest you ask about it on the boost-build list. -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (5)
-
Arjuna Balasingham
-
David Abrahams
-
Robert Ramey
-
Roman Neuhauser
-
Terence Wilson