I spent about two hours today trying to debug a race condition in a multi-threaded C++ app today… definitely not a fun thing to do. The worst part? The runtime diagnostics weren’t giving me anything useful to work with! Sometimes things just worked, sometimes I got segmentation faults inside old, well-tested parts of the application. At one point, I saw this error pop up:
pure virtual method called terminate called without an active exception Aborted
What? I know I can’t instantiate a class that has any pure-virtual methods, so how did this error show up? To debug it, I decided to replace all of the potentially-erroneous pure virtuals with stub functions that printed warnings to stderr. Lo and behold, I confirmed that polymorphism wasn’t working in my application. I had a bunch of Deriveds sitting in memory, and yet, the Base methods were being called.
Why was this happening? Because I was deleting objects while they were still in use. I don’t know if this is GCC-specific or not, but something very curious happens inside of destructors. Because the object hierarchy’s destructors get called from most-derived to least-derived, the object’s vtable switches up through parent classes. As a result, at some point in time (nondeterministic from a separate thread), my Derived objects were all really Bases. Calling a virtual member function on them in this mid-destruction state is what caused this situation.
Here’s about the simplest example I can think of that reproduces this situation:
#include <pthread.h>
#include <unistd.h>
struct base
{
virtual ~base() { sleep(1); }
virtual void func() = 0;
};
struct derived : public base
{
virtual ~derived() { }
virtual void func() { return; }
};
static void *thread_func(void* v)
{
base *b = reinterpret_cast<base*>(v);
while (true) b->func();
return 0;
}
int main()
{
pthread_t t;
base *b = new derived();
pthread_create(&t, 0, thread_func, b);
delete b;
return 0;
}
So what’s the moral of the story? If you ever see the error message pure virtual method called / terminate called without an active exception, check your object lifetimes! You may be trying to call members on a destructing (and thus incomplete) object. Don’t waste as much time as I did.

6 comments
Comments feed for this article
September 10, 2008 at 11:44 pm
Jeremy
It can also happen during construction.
In my case I have a base class that provides a thread for asynchronous processing. This is started in the base class constructor.
A derived class defines a thread function as well as pure virtual functions. The thread function can sometimes start calling the pure virtual functions before the later constructors are called in the ‘main’ thread.
My fix is inelegant – put a delay into the thread startup code.
There must be a better way?
May 10, 2009 at 6:35 pm
Steve Wolf
> My fix is inelegant — put a delay into the thread startup code.
> There must be a better way?
Yes there is — use a pthread_cond_t variable to synchronize between the threads. (An example of the following discussion is available at http://airwoof.org/pthread_example.c)
Before calling pthread_create, initialize a single cond and two locks in a structure you can pass to the new thread (if you’re already passing the thread data, you can use arg in the structure as well, as shown here):
typedef struct
{
pthread_mutex_t parentLock;
pthread_mutex_t childLock;
pthread_cond_t wait;
void* arg;
} wrapper_t;
wrapper_t threadData;
pthread_mutex_init(&threadData.parentLock, NULL);
pthread_mutex_init(&threadData.childLock, NULL);
pthread_cond_init(&threadData.wait, NULL);
Now grab the parent lock, create the thread, and wait for the child to grab its lock:
pthread_t tid;
int retval;
pthread_mutex_lock(&threadData.parentLock);
retval = pthread_create(&tid, NULL, startRoutine, &threadData);
if (retval == 0)
pthread_cond_wait(&threadData.wait, &threadData.parentLock);
pthread_mutex_unlock(&threadData.parentLock);
In the child thread’s create routine (e.g. startRoutine() used above), grab the child lock and signal the parent thread that it can proceed:
pthread_mutex_lock(&threadData.childLock);
pthread_mutex_lock(&threadData.parentLock);
pthread_cond_signal(&threadData.wait);
pthread_mutex_unlock(&threadData.parentLock);
Now both the threads can continue on their merry way doing their initializations. When the child thread gets to the point where it needs to know the objects in the main thread have been fully constructed, it waits on the parent thread:
pthread_cond_wait(&threadData.wait, &threadData.childLock);
pthread_mutex_unlock(&threadData.childLock);
When the parent thread knows that the objects are fully constructed, it wakes up the child thread. It has to grab the parent lock first, because there has to be one more handhake between parent and child before the parent can destroy the structure:
pthread_mutex_lock(&threadData.parentLock);
pthread_mutex_lock(&threadData.childLock);
pthread_cond_signal(&threadData.wait);
pthread_mutex_unlock(&threadData.childLock);
pthread_cond_wait(&threadData.wait, &threadData.parentLock);
The child thread wakes from its pthread_cond_wait() secure in the knowledge that it can use the objects with abandon.
It doesn’t matter which thread finishes the preliminaries first. If the parent finishes first, it will spin waiting for childLock before sending the signal. If the child finishes first, it will release the childLock (this is part of what pthread_cond_wait() does) and wait for the parent’s signal.
Now the child has to tell the parent that it’s never going to use the structure again:
pthread_mutex_lock(&threadData.parentLock);
pthread_cond_signal(&threadData.wait);
pthread_mutex_unlock(&threadData.parentLock);
At this point, the child thread can never touch threadData again, because the parent thread is going to destroy it.
The parent cleans up before exiting the block that created threadData:
pthread_mutex_unlock(&threadData.parentLock);
pthread_mutex_destroy(&threadData.parentLock);
pthread_mutex_destroy(&threadData.childLock);
pthread_cond_destroy(&threadData.wait);
At this point the synchronization is complete.
October 8, 2008 at 3:29 am
Gregory Dai
I ran into another scenario: automatic variable. When it was passed as an argument to pthread_create(), it was still there, but because execution of pthread_create() may be delayed, the automatic variable–a derived object–ran off the end of the (member) function.
I fixed it by using a member variable, which obviously lives longer than that function.
October 8, 2008 at 3:33 am
Gregory Dai
I meant execution of the thread made by pthread_create() may be delayed, not itself.
July 1, 2010 at 2:47 am
André Koscianski
Thank you so much! Got the same error, same reason. But, no threads.
In my case code was roughly like this:
“global” vector Gv;
Derived::Derived () { bla bla, Gv.push_back(this);}
void foo (void) { Derived obj; }
…
for (i = 0.. Gv.size() )
Gv[i]->foo2() = BOOM!
Simple correction:
void foo (void) { Derived *obj = new Derived(); }
, since object deletion is already carried out somewhere else
in the code.
Thanks again for sharing your finding.
June 12, 2012 at 11:58 am
dasith
I also got this error. Thank you very much for my time saving.