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
-~----------~----~----~----~------~----~------~--~---

Reply via email to