Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect unregistration (with exception thrown / crash) with multiple DLL's using Boost.Serialization #325

Open
gast128 opened this issue Jan 31, 2025 · 0 comments

Comments

@gast128
Copy link

gast128 commented Jan 31, 2025

We have the situation here that an application throws an unregistered_class exception in 'polymorphic::save' in 'oserializer.hpp' in the following code snippet:

const boost::serialization::extended_type_info * true_type =
    i.get_derived_extended_type_info(t);

// note:if this exception is thrown, be sure that derived pointer
// is either registered or exported.
if(NULL == true_type){
    boost::serialization::throw_exception(
        archive_exception(
            archive_exception::unregistered_class,
            "derived class not registered or exported"
        )
    );
}

The reason is that a type registered isn't present anymore.

We use Boost.Serialization as shared DLL with the following components:

  • COM component1 in DLL1 registering type e.g. Tracklet
  • COM component2 in DLL2 registering the same type (i.e. Tracklet)

If both COM components are loaded they both register their Tracklet type in singleton tkmap (which is a multiset). If COM component 1 gets unloaded Windows might unload DLL1 eventually. When a DLL gets unloaded it invokes shutdown code extended_type_info_typeid_0::type_unregister() which removes all instances of Tracklet from the multiset. If COM component2 now wants to serialize Tracklet it ends in an exception thrown in above code since the type is not registered anymore. The serialization will fail (and in our case even end program due to not catching exceptions there).

A solution might not be that difficult by only removing the type which is registered by the same object instance of extended_type_info_typeid_0. multiset has stable iterators so it could even hold the returned iterator and remove by that same iterator.

Alternatively only removing this pointer could be like this:

BOOST_SERIALIZATION_DECL void extended_type_info_typeid_0::type_unregister()
{
    if (nullptr != m_ti) {
        // note: previously this conditional was a runtime assertion with
        // BOOST_ASSERT.  We've changed it because we've discovered that at
        // least one platform is not guaranteed to destroy singletons in
        // reverse order of destruction.
        // BOOST_ASSERT(! singleton<tkmap>::is_destroyed());
        if(! singleton<tkmap>::is_destroyed()) {
            tkmap & x = singleton<tkmap>::get_mutable_instance();

            const auto pr = x.equal_range(this);

            for (auto it = pr.first; it != pr.second; ++it)
            {
                if (*it == this)
                {
                    x.erase(it);
                    break;
                }
            }
        }
    }
    m_ti = nullptr;
}

Using Boost 1.86; VS2022

Edit: some things and title.

@gast128 gast128 changed the title Crash with multiple DLL's using Boost.Serialization Exception thrown / crash with multiple DLL's using Boost.Serialization Jan 31, 2025
@gast128 gast128 changed the title Exception thrown / crash with multiple DLL's using Boost.Serialization Incorrect unregistration (with exception thrown / crash) with multiple DLL's using Boost.Serialization Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant