Technical Difficulties from on Top of the Mountain
2004-05-03
  Of course I would never do that
Once in a while you run into a problem, and for a considerable amount of time you are convinced that there is a bug in the compiler. However, it almost always turns out that no, its not a bug in the compiler, its an error in your code. I was going through that today, but it was partially due to the fact that the debugger was messing things up.

First of all, I'm working on multi-threaded code, which is always prone to strange behaviors and is very difficult to debug, but I wasn't really thinking that was of significance until I totally unwound the problem. There was unfortunately this delicate race condition which could make code which shouldn't work, suddenly work properly. Thus allowing me several hours of self indulgence as I mistakenly searched for the error in the compiler.

So I had a base class which needed to launch a thread and run its own handler:

class target
{
  public:
    target() ;
    virtual ~ target() ;

    void launch() ;
  private:
    virtual void run(void) ;
    static void * entry(void *) ;
} ;

void target::launch()
{
  pthread_t tmpthr ;
  pthread_create(& tmpthr, NULL, target::entry, this) ;
}
void * target::entry(void * atarget)
{
  target * ref= (target *) atarget ;
  ref-> run() ;
  return ref ;
}
and then I had a sub-class which overrode the run() method.
class monitor_class : public target
{
  public:
    monitor_class() ;

  protected:
    virtual void  run(void) ;
    ...
} ;
Now in the debugger, monitor_class::run() would run, but from the command line target::run() would run instead (as demonstrated through the judicial placement of printf's--knowing how to debug without a debugger is a necessary skill, for there are many circumstances in which a debugger is not available or not helpful in assessing the problem.) So clearly, there was some bug in the compiler and I had to figure out what it was, or at least work around it for the time being.

First I took a look at the typecast in target::entry() but except for switching to dynamic_cast<target*>(atarget) which didn't work in the debugger either, that wasn't helping me. I then tried making target::run() a pure virtual (by defining it virtual void run() = 0, but that just got me an exception at runtime: "pure virtual being called". I then worked backward and did a test call to run() in target::launch(), before doing all the casting. This was also calling the wrong function, and after staring at this for a minute or two I thought to myself to look at where I was calling launch().

Turns out I had decided to be clever and called launch() here:

target::target()
{
  launch() ;
}

Ouch. Never call a virtual function from a constructor, you don't get the answer you want. At best you get the methods that belong to the constructor class, at worst the results is undefined. Of course launch() wasn't virtual when I put it there. I must have decided to get clever later and wasn't watching for this side effect (and somehow the debugger pandered to my bad habits and kept me happy right up until I tried to run it stand-alone). Well, I'm certainly not going to do that again.

 
Comments: Post a Comment

<< Home
Life in the middle of nowhere, remote programming to try and support it, startups, children, and some tinkering when I get a chance.

ARCHIVES
January 2004 / February 2004 / March 2004 / April 2004 / May 2004 / June 2004 / July 2004 / August 2004 / September 2004 / October 2004 / November 2004 / December 2004 / January 2005 / February 2005 / March 2005 / April 2005 / May 2005 / June 2005 / July 2005 / August 2005 / September 2005 / October 2005 / November 2005 / December 2005 / January 2006 / February 2006 / March 2006 / April 2006 / May 2006 / June 2006 / July 2006 / August 2006 / September 2006 / October 2006 / November 2006 / December 2006 / January 2007 / February 2007 / March 2007 / April 2007 / June 2007 / July 2007 / August 2007 / September 2007 / October 2007 / November 2007 / December 2007 / January 2008 / May 2008 / June 2008 / August 2008 / February 2009 / August 2009 / February 2010 / February 2011 / March 2011 / October 2011 / March 2012 / July 2013 / August 2013 / September 2013 / October 2013 / November 2013 / December 2013 / December 2014 / February 2015 / March 2015 / July 2016 / September 2016 / December 2016 / April 2017 / June 2017 /


Blogroll
Paul Graham's Essays
You may not want to write in Lisp, but his advise on software, life and business is always worth listening to.
How to save the world
Dave Pollard working on changing the world .. one partially baked idea at a time.
SnowDeal
Eric Snowdeal IV - born 15 weeks too soon, now living a normal baby life.
Land and Hold Short
The life of a pilot.

The best of?
Jan '04
The second best villain of all times.

Feb '04
Oops I dropped by satellite.
New Jets create excitement in the air.
The audience is not listening.

Mar '04
Neat chemicals you don't want to mess with.
The Lack of Practise Effect

Apr '04
Scramjets take to the air
Doing dangerous things in the fire.
The Real Way to get a job

May '04
Checking out cool tools (with the kids)
A master geek (Ink Tank flashback)
How to play with your kids

Powered by Blogger