Subject: Re: [Boost-bugs] [Boost C++ Libraries] #4842: "pure virtual method called; terminate called without an active exception" on shutdown
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2011-03-19 20:27:48
#4842: "pure virtual method called; terminate called without an active exception"
on shutdown
-------------------------------+--------------------------------------------
Reporter: eric_niebler | Owner: ramey
Type: Bugs | Status: reopened
Milestone: To Be Determined | Component: serialization
Version: Boost 1.44.0 | Severity: Regression
Resolution: | Keywords: serialization singleton
-------------------------------+--------------------------------------------
Comment (by Aaron Barany <akb825@â¦>):
Though I can't enable that trap right now, I can say without a doubt that
it would be hit in my case. I have encountered other issues due to
serializers being instantiated in multiple libraries, which I provided a
patch for in ticket #5341. Unfortunately, in my use case it would be
nearly impossible to avoid serializing across shared library boundaries,
and I'm sure that's the case for a number of other users as well.
After looking at void_cast.cpp for a while and thinking about different
situations where there are multiple instances of void_casters, I think
that I have found a situation that would cause a crash. This situation can
also cause a crash if everything is statically linked.
First, I will point out an issue with the current deregistration method.
The first void caster that is constructed for a particular type relation
will be inserted into the set, and any duplicates will be ignored.
However, since it's doing a find and remove in recursive_unregister, the
frist void caster to be destructed will remove whichever void caster was
registered for that type relation, since it's comparing the type infos.
For example, if you have void casters A and B, which both represent the
same base and derived types, A will be registered on construction, while B
will be ignored. On destruction, B will be destructed first and remove A.
With the previous behavior, it was comparing pointers, so B wouldn't find
itself in the set, and A wouldn't be unregistered until A was destructed.
I will now lay out a particular case where this unregistration behavior
can cause a crash. Lets say you have a class hierarchy of A, B, C, and D,
where A is the base class and D is the most derived class. If void casters
are registered for A->B, B->C, and C->D, shortcuts will be made along the
way. Depending on the order of initialization, such as if C->D is
registered before B->C, those shortcuts can then then recursively create
shortcuts of their own. In this example, let's say the shortcut B->D
recursively creates the shortcut A->D, so the parent of A->D is the
shortcut for B->D.
Now we have our hierarchy of void casters set up. However, let's say
somewhere else in code the void caster B->D is registered directly, and is
constructed after all the void casters and resulting shortcuts above. That
void caster will see the B->D shortcut registered already, and won't
insert it into the set. When the program shuts down, that explicit B->D
void caster will be destructed first, since it was constructed last. When
that void caster is destructed, recursive_unregister will do a find for
the B->D type relation, and end up removing the shortcut registered
earlier. That shortcut is merely removed from the set, and is never
actually deleted, so it is leaked. As a result of that, the A->D shortcut
created by the B->D shortcut is never removed from the set, since its
parent's destructor is never called and is never recursively unregistered.
At some point, the type infos for A and D are destroyed, but that A->D
shortcut that references them is still left in the set. If there are still
void casters registered at that point, the next time a find is performed,
it will crash with the pure virtual function call.
Since order of construction at startup isn't guaranteed, this specific
ordering can occur regardless of if shared libraries are used or not. This
will generally occur if you are serializing polymorphic type hierarchies
by base pointer, as that serialization will register an explicit void
caster that can skip over multiple classes in the hierarchy and conflict
with an existing shortcut. I think there has been a correlation with the
use of shared libraries and experiencing this bug since projects with
large and complex type hierarchies are more likely to use shared
libraries.
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/4842#comment:23> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:06 UTC