On Thu, Apr 2, 2009 at 7:09 PM, cpu <c...@chromium.org> wrote: > > > > On Apr 2, 3:53 pm, Nicolas Sylvain <nsylv...@chromium.org> wrote: > > Another simple(r) example : > http://msdn.microsoft.com/en-us/library/t296ys27(VS.80).aspx > > > > <http://msdn.microsoft.com/en-us/library/t296ys27(VS.80).aspx>But, as > > discussed in bug 8544, we've see many purecall crashes that happens and > we > > don't > > think it's related to virtual functions. The only thing I can think of is > > that the vtable is corrupted. (overwritten or freed) > > > > Does it not make sense? > > I don't think you can overwrite a vtables because they should be in > the code section of the executable (the pages marked as read-execute), > they are known at compile time and it would not make sense to > construct them on the fly. > > But if you know of a case then that would be very interesting.
yes they should be protected with read/execute and besides, you'd have to overwrite entries in the vtable with a pointer to __purecall for that to happen > > > > > > > Nicolas > > > > > > > > On Thu, Apr 2, 2009 at 1:54 PM, cpu <c...@chromium.org> wrote: > > > > > After reading some speculation in bugs such as > > >http://code.google.com/p/chromium/issues/detail?id=8544I 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-pi. > .. > > > > > -cpu > > > --~--~---------~--~----~------------~-------~--~----~ Chromium Developers mailing list: chromium-dev@googlegroups.com View archives, change email options, or unsubscribe: http://groups.google.com/group/chromium-dev -~----------~----~----~----~------~----~------~--~---