Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions src/extended_type_info_typeid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,16 @@ extended_type_info_typeid_0::type_unregister()
// BOOST_ASSERT(! singleton<tkmap>::is_destroyed());
if(! singleton<tkmap>::is_destroyed()){
tkmap & x = singleton<tkmap>::get_mutable_instance();

// remove all entries in map which corresponds to this type
// make sure that we don't use any invalidated iterators
while(true){
const tkmap::iterator & it = x.find(this);
if(it == x.end())
tkmap::iterator start = x.lower_bound(this);
const tkmap::iterator end = x.upper_bound(this);
// Entries compare equal when they describe the same type, and
// another module may well have registered that same type. Erase
// this entry alone, as key_unregister does.
for(; start != end; ++start){
if(this == *start){
x.erase(start);
break;
x.erase(it);
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ if ! $(BOOST_ARCHIVE_LIST) {
[ test-bsl-run test_dll_base_pointer : : dll_polymorphic_base dll_polymorphic_derived2 : <link>static:<build>no ]
# [ test-bsl-run test_dll_plugin : : dll_derived2 : <link>static:<build>no <target-os>linux:<linkflags>-ldl ]

[ test-bsl-run test_duplicate_type_registration ]
[ test-bsl-run test_private_ctor ]
[ test-bsl-run test_reset_object_address : A ]
[ test-bsl-run test_void_cast ]
Expand Down
64 changes: 64 additions & 0 deletions test/test_duplicate_type_registration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// test_duplicate_type_registration.cpp

// Copyright 2026 Gennaro Prota.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// See http://www.boost.org for updates, documentation, and revision history.

// Every module linked against the library registers the types it serializes,
// so the type registry holds one entry per module per type. A module going
// away has to take its own entry with it and leave the others alone, or
// serialization stops working in the modules still running.

// Reported by gast128 in
// https://github.com/boostorg/serialization/issues/325, from two COM
// components in separate DLLs registering the same type: unloading one of
// them made the other throw unregistered_class. Both the diagnosis and the
// remedy in the report were right. Thanks for the careful write up!

// singleton<T> explicitly allows a class derived from it to be instantiated
// more than once, which is what stands in for the second module below.

#include <cstddef>

// The lightweight test of Boost.Core is used here in place of
// test_tools.hpp, whose main locks the singleton module while the test runs,
// so that the type registry cannot change. Loading and unloading a module
// changes it while the program runs, which is the very thing under test.
#include <boost/core/lightweight_test.hpp>

#include <boost/serialization/extended_type_info_typeid.hpp>
#include <boost/serialization/singleton.hpp>

struct base {
virtual ~base(){}
};

struct derived : base {
};

typedef boost::serialization::extended_type_info_typeid<derived> eti_derived;

int
main(){
const eti_derived & first =
boost::serialization::singleton<eti_derived>::get_const_instance();

const derived d;
BOOST_TEST(NULL != first.get_derived_extended_type_info(d));

{
// A second module registers the same type.
const eti_derived second;
BOOST_TEST(NULL != first.get_derived_extended_type_info(d));
BOOST_TEST(NULL != second.get_derived_extended_type_info(d));
}
// The second module is unloaded here.

BOOST_TEST(NULL != first.get_derived_extended_type_info(d));

return boost::report_errors();
}