After reading some speculation in bugs such as http://code.google.com/p/chromium/issues/detail?id=8544 I felt compelled to dispel some myths and misunderstandings about the origin and meaning of the mythical _purecall_ exception. My hope is that then you can spot the problems in our source code and fix them. Sorry for the long post.
So first of all, what do you see when you get this error? if you are in a debug build and you are not eating the exceptions via some custom handler you see this dialog: --------------------------- Debug Error! R6025 - pure virtual function call (Press Retry to debug the application) --------------------------- Abort Retry Ignore --------------------------- For chrome/chromium we install a special handler, which forces a crash dump in which case you'll see in in the debugger analysis something like this: [chrome_dll_main.cc:100] - `anonymous namespace'::PureCall() [purevirt.c:47] - _purecall Before going into too much detail, let me show you a small program that causes this exception: ================================= class Base { public: virtual ~Base() { ThreeFn(); } virtual void OneFn() = 0; virtual void TwoFn() = 0; void ThreeFn() { OneFn(); TwoFn(); } }; class Concrete : public Base { public: Concrete() : state_(0) { } virtual void OneFn() { state_ += 1; } virtual void TwoFn() { state_ += 2; } private: int state_; }; int _tmain(int argc, _TCHAR* argv[]) { Concrete* obj = new Concrete(); obj->OneFn(); obj->TwoFn(); obj->ThreeFn(); delete obj; return 0; } ================================= Can you spot the problem? do you know at which line it crashes, do you know why? if so I have wasted your time, apologies. If you are unsure then read on. This program crashes when trying to call OneFn() with a purecall exception on debug build. On release build it exits with no error, but your mileage might vary depending on what optimizations are active. The call stack for the crash is: msvcr80d.dll!__purecall() + 0x25 <------ shows the dialog (debug only) app.exe!Base::ThreeFn() Line 16 + 0xfc <----- error here app.exe!Base::~Base() Line 10 C++ app.exe!Concrete::~Concrete() + 0x2b app.exe!Concrete::`scalar deleting destructor'() + 0x2b <----- delete obj So as you have guessed it has to do with calling virtual functions from a destructor. What happens is that during construction an object evolves from the earliest base class to the actual type and during destruction the object devolves (is that a word?) from the actual object to the earliest base class; when we reach ~Base() body the object is no longer of type Concrete but of type Base and thus the call Base::OneFn () is an error because that class does not in fact have any implementation. What the compiler does is create two vtables, the vtable of Concrete looks like this: vtable 1: [ 0 ] -> Concrete::OneFn() [ 1 ] -> Concrete::TwoFn() vtable 2: [ 0 ]-> msvcr80d.dll!__purecall() [ 1 ]-> msvcr80d.dll!__purecall() The dtor of Concrete is the default dtor which does nothing except calling Base::~Base(), but the dtor of base does: this->vtbl_ptr = vtable2 call ThreeFn() Now, why doesn't the release build crash? That's because the compiler does not bother with generating the second vtable, after all is not going to be used and thus also eliminates the related lines such as this->vtbl_ptr = vtable2. Therefore the object reaches the base dtor with the vtbl_ptr pointing to vtable1 which makes the call ThreeFn() just work. But that was just luck. If you ever modify the base class, such as introducing a new virtual function that is not pure, like this: class Base { public: virtual ~Base() { ThreeFn(); } virtual void OneFn() = 0; virtual void TwoFn() = 0; virtual void FourFn() { <--- new function, not pure virtual wprintf(L"aw snap"); } void ThreeFn() { OneFn(); TwoFn(); } }; // Same program below. // ....... // ======================== Then you are forcing the compiler to generate vtable 2, which looks: vtable 2: [ 0 ]-> msvcr80d.dll!__purecall() [ 1 ]-> msvcr80d.dll!__purecall() [ 2 [-> Base::FourFn() And now the purecall crash magically happens (on the same spot) on release builds, which is quite surprising since the trigger was the introduction of FourFn() which has _nothing_ to do with the crash or the problem and is many commits after the introduction of the problem. So the moral of the story? beware of virtual calls on dtors and ctors. Note that in practice this is quite tricky because of layers of indirection / complexity of the code base. ... so and what about the manbearpig ? Ah, yes no longer a myth: http://www.thinkgene.com/scientists-successfully-create-human-bear-pig-chimera/ -cpu --~--~---------~--~----~------------~-------~--~----~ Chromium Developers mailing list: chromium-dev@googlegroups.com View archives, change email options, or unsubscribe: http://groups.google.com/group/chromium-dev -~----------~----~----~----~------~----~------~--~---