[chromium-dev] Re: PSA: Virtual dispatch doesn't work (as you might expect) in destructors!

2009-10-31 Thread Erik Kay

On Fri, Oct 30, 2009 at 5:09 PM, David Levin le...@chromium.org wrote:


 On Fri, Oct 30, 2009 at 3:59 PM, Antoine Labour pi...@google.com wrote:


 On Fri, Oct 30, 2009 at 3:54 PM, Jeremy Orlow jor...@chromium.org wrote:

 On Fri, Oct 30, 2009 at 3:46 PM, Scott Hess sh...@chromium.org wrote:

 Just to be clear for those of us who are wobbly on C++, this is
 because during the constructor or destructor, your object is of the
 class in question, NOT of the class it will finally be, because in the
 constructor the subclass has not been constructed, yet, and in the
 destructor the subclass was already destructed.  So calling to the
 subclass virtual implementation would be bad.

 Scott Meyers says: http://www.artima.com/cppsource/nevercall.html

 Is there any way we could modify an object to assert that it can't
 happen in development?  Like scoped_vtable_killer declared in the
 constructor and destructor which makes calling a virtual method on
 that object fatal?

 Or is there any sort of built in compiler warning that we could turn on?
  I did a bit of searching and was really surprised that I couldn't find any
 mention of such a thing.

 The compiler could find if it's called directly from the destructor, but
 there's no way it'd find your case ! The virtual call happens on another
 thread.
 To Scott's question: you can blit NULL into the vtable field, if you know
 where it is (it's not too hard, but depends on the compiler). You'll know if
 you call it - you'll die.

 For the original issue this doesn't work b/c for virtual calls in the
 constructor/destructor, the compiler may optimize them to be non-virtual.

Good point.  Given this, I'd suggest that the poison vtable approach
would be better implemented as a compiler feature.  When the flag is
enabled, the compiler would specifically avoid these optimizations.
Perhaps this would only work in debug builds.

Erik


 Also, it looks like this keeps biting
 chromium: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33475


 Better yet, you could have a static table of functions that print a
 message before dying and blit that one, but that gets trickier.
 Antoine


 


--~--~-~--~~~---~--~~
Chromium Developers mailing list: chromium-dev@googlegroups.com 
View archives, change email options, or unsubscribe: 
http://groups.google.com/group/chromium-dev
-~--~~~~--~~--~--~---



[chromium-dev] Re: PSA: Virtual dispatch doesn't work (as you might expect) in destructors!

2009-10-30 Thread Adam Barth

I'm sorry for introducing this pattern in base::Thread.  It's bitten
use several times over the course of the project.  If you see a better
design, please don't hesitate to fix it.

Adam


On Fri, Oct 30, 2009 at 3:12 PM, Jeremy Orlow jor...@chromium.org wrote:
 I've spent a good deal of this week trying to track down what turned out to
 be a simple but fairly common problem: I forgot virtual dispatch only
 partially works in destructors.  There have been several email threads about
 this, but it still bites us form time to time, so I thought it was worth
 another reminder.

 Details:
 I subclassed ChromeThread which subclasses base::Thread.  base::Thread calls
 CleanUp on the thread right before termination.  CleanUp is virtual.  Both
 ChromeThread and my class override CleanUp().  base::Thread calls Stop() in
 its destructor to stop the thread (if it hasn't already been stopped).  But
 by the time you hit destruction, the vtable is no longer available and thus
 the destructor of base::Thread (and anything it calls) does NOT have access
 to the vtable of ChromeThread (or my class).  So, if you don't explicitly
 call Stop(), your subclass's CleanUp method will NOT be called.  Thus the
 thread was going away without my CleanUp method ever being called.
 Obviously this affects more than just base::Thread.  And this is also how
 you can hit errors with pure virtual methods being called.
 J
 


--~--~-~--~~~---~--~~
Chromium Developers mailing list: chromium-dev@googlegroups.com 
View archives, change email options, or unsubscribe: 
http://groups.google.com/group/chromium-dev
-~--~~~~--~~--~--~---



[chromium-dev] Re: PSA: Virtual dispatch doesn't work (as you might expect) in destructors!

2009-10-30 Thread Antoine Labour
On Fri, Oct 30, 2009 at 3:12 PM, Jeremy Orlow jor...@chromium.org wrote:

 I've spent a good deal of this week trying to track down what turned out to
 be a simple but fairly common problem: I forgot virtual dispatch only
 partially works in destructors.  There have been several email threads about
 this, but it still bites us form time to time, so I thought it was worth
 another reminder.


 Details:
 I subclassed ChromeThread which subclasses base::Thread.  base::Thread
 calls CleanUp on the thread right before termination.  CleanUp is virtual.
  Both ChromeThread and my class override CleanUp().  base::Thread calls
 Stop() in its destructor to stop the thread (if it hasn't already been
 stopped).  But by the time you hit destruction, the vtable is no longer
 available and thus the destructor of base::Thread (and anything it calls)
 does NOT have access to the vtable of ChromeThread (or my class).  So, if
 you don't explicitly call Stop(), your subclass's CleanUp method will NOT be
 called.  Thus the thread was going away without my CleanUp method ever being
 called.

 Obviously this affects more than just base::Thread.  And this is also how
 you can hit errors with pure virtual methods being called.

 J


Suggestion: don't call  CleanUp in the destructor, but check that someone
did.

Antoine

--~--~-~--~~~---~--~~
Chromium Developers mailing list: chromium-dev@googlegroups.com 
View archives, change email options, or unsubscribe: 
http://groups.google.com/group/chromium-dev
-~--~~~~--~~--~--~---



[chromium-dev] Re: PSA: Virtual dispatch doesn't work (as you might expect) in destructors!

2009-10-30 Thread Antoine Labour
On Fri, Oct 30, 2009 at 3:26 PM, Jeremy Orlow jor...@chromium.org wrote:

 On Fri, Oct 30, 2009 at 3:17 PM, Antoine Labour pi...@google.com wrote:

 On Fri, Oct 30, 2009 at 3:12 PM, Jeremy Orlow jor...@chromium.orgwrote:

 I've spent a good deal of this week trying to track down what turned out
 to be a simple but fairly common problem: I forgot virtual dispatch only
 partially works in destructors.  There have been several email threads about
 this, but it still bites us form time to time, so I thought it was worth
 another reminder.


 Details:
 I subclassed ChromeThread which subclasses base::Thread.  base::Thread
 calls CleanUp on the thread right before termination.  CleanUp is virtual.
  Both ChromeThread and my class override CleanUp().  base::Thread calls
 Stop() in its destructor to stop the thread (if it hasn't already been
 stopped).  But by the time you hit destruction, the vtable is no longer
 available and thus the destructor of base::Thread (and anything it calls)
 does NOT have access to the vtable of ChromeThread (or my class).  So, if
 you don't explicitly call Stop(), your subclass's CleanUp method will NOT be
 called.  Thus the thread was going away without my CleanUp method ever being
 called.

 Obviously this affects more than just base::Thread.  And this is also how
 you can hit errors with pure virtual methods being called.

 J


 Suggestion: don't call  CleanUp in the destructor, but check that someone
 did.


 I assume you mean Stop()?


Yes, sorry, looking at the code, that's what I meant.



 The problem is when you have a class like ChromeThread inherit from
 base::Thread and then call Stop() in its destructor and then have someone
 else subclass ChromeThread and expect its CleanUp to be called.


Yup, the pattern is dangerous, so instead of relying on Stop being called
from the destructor, it should be explicitly done by the client (and moving
Stop() to ~ChromeThread will only move the problem), and the destructor
should check that it has been done.

Antoine




 On Fri, Oct 30, 2009 at 3:16 PM, Adam Barth aba...@chromium.org wrote:

 I'm sorry for introducing this pattern in base::Thread.  It's bitten
 use several times over the course of the project.  If you see a better
 design, please don't hesitate to fix it.

 Adam


 Already filed a bug: http://crbug.com/26365


--~--~-~--~~~---~--~~
Chromium Developers mailing list: chromium-dev@googlegroups.com 
View archives, change email options, or unsubscribe: 
http://groups.google.com/group/chromium-dev
-~--~~~~--~~--~--~---



[chromium-dev] Re: PSA: Virtual dispatch doesn't work (as you might expect) in destructors!

2009-10-30 Thread Scott Hess

Just to be clear for those of us who are wobbly on C++, this is
because during the constructor or destructor, your object is of the
class in question, NOT of the class it will finally be, because in the
constructor the subclass has not been constructed, yet, and in the
destructor the subclass was already destructed.  So calling to the
subclass virtual implementation would be bad.

Scott Meyers says: http://www.artima.com/cppsource/nevercall.html

Is there any way we could modify an object to assert that it can't
happen in development?  Like scoped_vtable_killer declared in the
constructor and destructor which makes calling a virtual method on
that object fatal?

-scott


On Fri, Oct 30, 2009 at 3:12 PM, Jeremy Orlow jor...@chromium.org wrote:
 I've spent a good deal of this week trying to track down what turned out to
 be a simple but fairly common problem: I forgot virtual dispatch only
 partially works in destructors.  There have been several email threads about
 this, but it still bites us form time to time, so I thought it was worth
 another reminder.

 Details:
 I subclassed ChromeThread which subclasses base::Thread.  base::Thread calls
 CleanUp on the thread right before termination.  CleanUp is virtual.  Both
 ChromeThread and my class override CleanUp().  base::Thread calls Stop() in
 its destructor to stop the thread (if it hasn't already been stopped).  But
 by the time you hit destruction, the vtable is no longer available and thus
 the destructor of base::Thread (and anything it calls) does NOT have access
 to the vtable of ChromeThread (or my class).  So, if you don't explicitly
 call Stop(), your subclass's CleanUp method will NOT be called.  Thus the
 thread was going away without my CleanUp method ever being called.
 Obviously this affects more than just base::Thread.  And this is also how
 you can hit errors with pure virtual methods being called.
 J
 


--~--~-~--~~~---~--~~
Chromium Developers mailing list: chromium-dev@googlegroups.com 
View archives, change email options, or unsubscribe: 
http://groups.google.com/group/chromium-dev
-~--~~~~--~~--~--~---



[chromium-dev] Re: PSA: Virtual dispatch doesn't work (as you might expect) in destructors!

2009-10-30 Thread Jeremy Orlow
On Fri, Oct 30, 2009 at 3:46 PM, Scott Hess sh...@chromium.org wrote:

 Just to be clear for those of us who are wobbly on C++, this is
 because during the constructor or destructor, your object is of the
 class in question, NOT of the class it will finally be, because in the
 constructor the subclass has not been constructed, yet, and in the
 destructor the subclass was already destructed.  So calling to the
 subclass virtual implementation would be bad.

 Scott Meyers says: http://www.artima.com/cppsource/nevercall.html

 Is there any way we could modify an object to assert that it can't
 happen in development?  Like scoped_vtable_killer declared in the
 constructor and destructor which makes calling a virtual method on
 that object fatal?


Or is there any sort of built in compiler warning that we could turn on?  I
did a bit of searching and was really surprised that I couldn't find any
mention of such a thing.

On Fri, Oct 30, 2009 at 3:12 PM, Jeremy Orlow jor...@chromium.org wrote:
  I've spent a good deal of this week trying to track down what turned out
 to
  be a simple but fairly common problem: I forgot virtual dispatch only
  partially works in destructors.  There have been several email threads
 about
  this, but it still bites us form time to time, so I thought it was worth
  another reminder.
 
  Details:
  I subclassed ChromeThread which subclasses base::Thread.  base::Thread
 calls
  CleanUp on the thread right before termination.  CleanUp is virtual.
  Both
  ChromeThread and my class override CleanUp().  base::Thread calls Stop()
 in
  its destructor to stop the thread (if it hasn't already been stopped).
  But
  by the time you hit destruction, the vtable is no longer available and
 thus
  the destructor of base::Thread (and anything it calls) does NOT have
 access
  to the vtable of ChromeThread (or my class).  So, if you don't explicitly
  call Stop(), your subclass's CleanUp method will NOT be called.  Thus the
  thread was going away without my CleanUp method ever being called.
  Obviously this affects more than just base::Thread.  And this is also how
  you can hit errors with pure virtual methods being called.
  J
   
 


--~--~-~--~~~---~--~~
Chromium Developers mailing list: chromium-dev@googlegroups.com 
View archives, change email options, or unsubscribe: 
http://groups.google.com/group/chromium-dev
-~--~~~~--~~--~--~---



[chromium-dev] Re: PSA: Virtual dispatch doesn't work (as you might expect) in destructors!

2009-10-30 Thread Michael Nordman
On Fri, Oct 30, 2009 at 3:46 PM, Scott Hess sh...@chromium.org wrote:


 Just to be clear for those of us who are wobbly on C++, this is
 because during the constructor or destructor, your object is of the
 class in question, NOT of the class it will finally be, because in the
 constructor the subclass has not been constructed, yet, and in the
 destructor the subclass was already destructed.  So calling to the
 subclass virtual implementation would be bad.

 Scott Meyers says: http://www.artima.com/cppsource/nevercall.html

 Is there any way we could modify an object to assert that it can't
 happen in development?  Like scoped_vtable_killer declared in the
 constructor and destructor which makes calling a virtual method on
 that object fatal?


That's an intriguing idea. It seems like you could swap the real vtable ptr
out on ctor/dtor entry, and replace it with a ptr to a poisoned vtable. This
sounds like debug build stuff only.



 -scott


 On Fri, Oct 30, 2009 at 3:12 PM, Jeremy Orlow jor...@chromium.org wrote:
  I've spent a good deal of this week trying to track down what turned out
 to
  be a simple but fairly common problem: I forgot virtual dispatch only
  partially works in destructors.  There have been several email threads
 about
  this, but it still bites us form time to time, so I thought it was worth
  another reminder.
 
  Details:
  I subclassed ChromeThread which subclasses base::Thread.  base::Thread
 calls
  CleanUp on the thread right before termination.  CleanUp is virtual.
  Both
  ChromeThread and my class override CleanUp().  base::Thread calls Stop()
 in
  its destructor to stop the thread (if it hasn't already been stopped).
  But
  by the time you hit destruction, the vtable is no longer available and
 thus
  the destructor of base::Thread (and anything it calls) does NOT have
 access
  to the vtable of ChromeThread (or my class).  So, if you don't explicitly
  call Stop(), your subclass's CleanUp method will NOT be called.  Thus the
  thread was going away without my CleanUp method ever being called.
  Obviously this affects more than just base::Thread.  And this is also how
  you can hit errors with pure virtual methods being called.
  J
  
 

 


--~--~-~--~~~---~--~~
Chromium Developers mailing list: chromium-dev@googlegroups.com 
View archives, change email options, or unsubscribe: 
http://groups.google.com/group/chromium-dev
-~--~~~~--~~--~--~---



[chromium-dev] Re: PSA: Virtual dispatch doesn't work (as you might expect) in destructors!

2009-10-30 Thread Scott Hess

On Fri, Oct 30, 2009 at 3:54 PM, Jeremy Orlow jor...@chromium.org wrote:
 On Fri, Oct 30, 2009 at 3:46 PM, Scott Hess sh...@chromium.org wrote:
 Just to be clear for those of us who are wobbly on C++, this is
 because during the constructor or destructor, your object is of the
 class in question, NOT of the class it will finally be, because in the
 constructor the subclass has not been constructed, yet, and in the
 destructor the subclass was already destructed.  So calling to the
 subclass virtual implementation would be bad.

 Scott Meyers says: http://www.artima.com/cppsource/nevercall.html

 Is there any way we could modify an object to assert that it can't
 happen in development?  Like scoped_vtable_killer declared in the
 constructor and destructor which makes calling a virtual method on
 that object fatal?

 Or is there any sort of built in compiler warning that we could turn on?  I
 did a bit of searching and was really surprised that I couldn't find any
 mention of such a thing.

It would have to be a really smart compiler, because you could call a
function which calls another object's function which calls back to a
virtual in your object.  That's why I suggested a way to make vtable
references fatal, so at least when doing development you could get a
notification (and not check it in).

-scott

--~--~-~--~~~---~--~~
Chromium Developers mailing list: chromium-dev@googlegroups.com 
View archives, change email options, or unsubscribe: 
http://groups.google.com/group/chromium-dev
-~--~~~~--~~--~--~---



[chromium-dev] Re: PSA: Virtual dispatch doesn't work (as you might expect) in destructors!

2009-10-30 Thread Antoine Labour
On Fri, Oct 30, 2009 at 3:54 PM, Jeremy Orlow jor...@chromium.org wrote:

 On Fri, Oct 30, 2009 at 3:46 PM, Scott Hess sh...@chromium.org wrote:

 Just to be clear for those of us who are wobbly on C++, this is
 because during the constructor or destructor, your object is of the
 class in question, NOT of the class it will finally be, because in the
 constructor the subclass has not been constructed, yet, and in the
 destructor the subclass was already destructed.  So calling to the
 subclass virtual implementation would be bad.

 Scott Meyers says: http://www.artima.com/cppsource/nevercall.html

 Is there any way we could modify an object to assert that it can't
 happen in development?  Like scoped_vtable_killer declared in the
 constructor and destructor which makes calling a virtual method on
 that object fatal?


 Or is there any sort of built in compiler warning that we could turn on?  I
 did a bit of searching and was really surprised that I couldn't find any
 mention of such a thing.


The compiler could find if it's called directly from the destructor, but
there's no way it'd find your case ! The virtual call happens on another
thread.

To Scott's question: you can blit NULL into the vtable field, if you know
where it is (it's not too hard, but depends on the compiler). You'll know if
you call it - you'll die.
Better yet, you could have a static table of functions that print a message
before dying and blit that one, but that gets trickier.

Antoine



 On Fri, Oct 30, 2009 at 3:12 PM, Jeremy Orlow jor...@chromium.org wrote:
  I've spent a good deal of this week trying to track down what turned out
 to
  be a simple but fairly common problem: I forgot virtual dispatch only
  partially works in destructors.  There have been several email threads
 about
  this, but it still bites us form time to time, so I thought it was worth
  another reminder.
 
  Details:
  I subclassed ChromeThread which subclasses base::Thread.  base::Thread
 calls
  CleanUp on the thread right before termination.  CleanUp is virtual.
  Both
  ChromeThread and my class override CleanUp().  base::Thread calls Stop()
 in
  its destructor to stop the thread (if it hasn't already been stopped).
  But
  by the time you hit destruction, the vtable is no longer available and
 thus
  the destructor of base::Thread (and anything it calls) does NOT have
 access
  to the vtable of ChromeThread (or my class).  So, if you don't
 explicitly
  call Stop(), your subclass's CleanUp method will NOT be called.  Thus
 the
  thread was going away without my CleanUp method ever being called.
  Obviously this affects more than just base::Thread.  And this is also
 how
  you can hit errors with pure virtual methods being called.
  J
  
 



 


--~--~-~--~~~---~--~~
Chromium Developers mailing list: chromium-dev@googlegroups.com 
View archives, change email options, or unsubscribe: 
http://groups.google.com/group/chromium-dev
-~--~~~~--~~--~--~---



[chromium-dev] Re: PSA: Virtual dispatch doesn't work (as you might expect) in destructors!

2009-10-30 Thread David Levin
On Fri, Oct 30, 2009 at 3:59 PM, Antoine Labour pi...@google.com wrote:



 On Fri, Oct 30, 2009 at 3:54 PM, Jeremy Orlow jor...@chromium.org wrote:

 On Fri, Oct 30, 2009 at 3:46 PM, Scott Hess sh...@chromium.org wrote:

 Just to be clear for those of us who are wobbly on C++, this is
 because during the constructor or destructor, your object is of the
 class in question, NOT of the class it will finally be, because in the
 constructor the subclass has not been constructed, yet, and in the
 destructor the subclass was already destructed.  So calling to the
 subclass virtual implementation would be bad.

 Scott Meyers says: http://www.artima.com/cppsource/nevercall.html

 Is there any way we could modify an object to assert that it can't
 happen in development?  Like scoped_vtable_killer declared in the
 constructor and destructor which makes calling a virtual method on
 that object fatal?


 Or is there any sort of built in compiler warning that we could turn on?
  I did a bit of searching and was really surprised that I couldn't find any
 mention of such a thing.


 The compiler could find if it's called directly from the destructor, but
 there's no way it'd find your case ! The virtual call happens on another
 thread.

 To Scott's question: you can blit NULL into the vtable field, if you know
 where it is (it's not too hard, but depends on the compiler). You'll know if
 you call it - you'll die.


For the original issue this doesn't work b/c for virtual calls in the
constructor/destructor, the compiler may optimize them to be non-virtual.

Also, it looks like this keeps biting chromium:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33475


Better yet, you could have a static table of functions that print a message
 before dying and blit that one, but that gets trickier.

 Antoine



--~--~-~--~~~---~--~~
Chromium Developers mailing list: chromium-dev@googlegroups.com 
View archives, change email options, or unsubscribe: 
http://groups.google.com/group/chromium-dev
-~--~~~~--~~--~--~---