On Fri, Apr 3, 2009 at 12:15 PM, Huan Ren <hu...@google.com> wrote: > Based on what I saw in the bug, it looks like an exception happening > during CALL instruction may lead to PureCall(). > > For example, an object obj has been freed and later on someone calls > obj->func(). Then the assembly code looks like this: > > // ecx: pointer to obj which is in memory > // [ecx]: supposed to be pointer to vtable, it has invalid value since > obj is freed > // edx: now has pointer to vtable, which is invalid > mov edx,dword ptr [ecx] > > // deref the vtable and make the call > call dword ptr [edx+4] > > When a (hardware) exception happens during the call instruction, the > control will be eventually transfered to the routine handling this > type of exception which I *think* is PureCall(). > > Huan > > On Fri, Apr 3, 2009 at 11:26 AM, Ricardo Vargas <rvar...@chromium.org> wrote: >> I certainly don't want to imply that it is the case with this particular >> bug, but I have seen crashes when the cause of the problem is using an >> object that was previously deleted (and only end up with this exception when >> all the planets are properly aligned). I guess that it depends on the actual >> class hierarchy of the objects in question, but I'd think that "simple" >> examples end up on a lot of crashes right after the cl that exposes the >> problem. >> >> On Fri, Apr 3, 2009 at 12:52 AM, Dean McNamee <de...@chromium.org> wrote: >>> >>> You could, however, corrupt the vtable pointer (not the vtable). Say >>> somehow 32 was added to it, now the table is misaligned, and you might >>> get a purecall, etc. Not sure that's likely at all though. >>> >>> Since the vtable pointer is the first field, it seems ripe for >>> problems w/ use after free, etc. I kinda doubt that's what's >>> happening here though. Anyone who is working on one of these can bug >>> me and I'll look at the crash dump. >>> >>> On Fri, Apr 3, 2009 at 7:24 AM, Tommi <to...@chromium.org> wrote: >>> > 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 -~----------~----~----~----~------~----~------~--~---