February, 2008

Larry Osterman's WebLog

Confessions of an Old Fogey
  • Larry Osterman's WebLog

    Casting from one interface to another...

    • 34 Comments

    A co-worker came by to ask what he thought was a coding "style" question that turned into a correctness issue, and I thought I'd share it.

     

    Someone had defined two COM interfaces:

    interface IFoo : IUnknown
    {
        HRESULT FooMethod1();
        HRESULT FooMethod2();
    }

    They also had a factory interface IBar which had a method HRESULT GetFoo(IFoo **ppFoo).

     

    As a result of new work, the team that owned IFoo wanted to extend IFoo.  To do this, they defined a new interface, IFoo2 that inherited from IFoo:

    interface IFoo2 : IFoo
    {
        HRESULT Foo2Method1();
        HRESULT Foo2Method2();
    }

    The team that owned IFoo (and IBar) decided that they didn't want to change the IBar interface to add a GetFoo2 method, feeling that the GetFoo method was "good enough".

    My co-worker wanted to call GetFoo and cast the resulting IFoo object into an IFoo2 object (he knew that the IFoo he got was always going to be an IFoo2).  He was worried about the stylistic implications of doing the cast.

     

    The problem with doing this turns out not to be a style issue, but instead to be correctness issue.  Here's the problem.

    Somewhere under the covers, there's a class CFoo that implements IFoo and IFoo2.  This is the object that will be returned by the IBar::GetFoo method.

    When the compiler lays out this object, the compiler will lay out the data for the class as follows:

    1 CFoo vtable
    2 IFoo vtable with 1*sizeof(void *) adjustor thunk
    3 IFoo2 vtable with 2*sizeof(void *) adjustor thunk
    4 CFoo member variable 1 storage
    5 CFoo member variable 2 storage
    6 :
    : :

    When IBar::GetFoo returns, it returns a pointer to the 2nd element of the class (the adjustor thunk will ensure that the right thing happens when you call into the member functions).

    The IFoo vtable is laid out in memory like this:

    1 QueryInterface()
    2 AddRef()
    3 Release()
    4 FooMethod1()
    5 FooMethod2()

    The IFoo2 vtable on the other hand is laid out in memory like this:

    1 QueryInterface()
    2 AddRef()
    3 Release()
    4 FooMethod1()
    5 FooMethod2()
    6 Foo2Method1()
    7 Foo2Method2()

    When the caller calls into a method on IFoo, the compiler will index into the vtable to find the pointer to the code that implements the specified method.  By casting from an IFoo to an IFoo2, my co-worker was telling the compiler "I know that this thing is also an IFoo2, so you should act like the vtable is really an IFoo2 vtable.

     

    The first time that he called into Foo2Method1 or Foo2Method2 using this mechanism, if he was lucky, his code would crash.  If he was unlucky (and the random chunk of memory sitting at the end of the vtable for IFoo happened to be code that matched the function signature of Foo2Method2, he would simply corrupt memory.

    All-in-all, a bad thing to do.

    In addition, if the particular class implementation of IFoo chose to implement IFoo2 via COM aggregation (in other words, using the delegator pattern), his cast would defeat that.

     

    The right thing to do in this case is to call QueryInterface on the IFoo object looking for IFoo2, then release the IFoo object since it's no longer needed.

     

    Edit: Fixed typos.

  • Larry Osterman's WebLog

    "We're back and..."

    • 15 Comments

    Raymond sent me an email yesterday asking me to confirm an old Lan Manager slogan.

    Back in the Lanman 2.0 days, Brian Valentine (who ran the Lanman group) made up a series of T-Shirts for the team with the words:

    Lan Manager... We're back and we're BAD". 

    I believe I still have one of those t-shirts.  It had a relatively snarky attitude, which I love (and why I loved working for Brian, he shared many of the same sentiments).  For the non-english speakers reading this, the use of "BAD" is an American idiom that means "nasty, in a really good way".

     

    The reason that Raymond asked me the question was because of what apparently happened to the T-Shirt when it hit our international subsidiaries.  Not surprisingly, many of them wanted to print up their own version, but sometimes the results were... less than perfect.  According to one person, the Swedish had a hard time translating the "BAD" idiom.  So they apparently fell back on a literal translation of the slogan and printed up their own t-shirts, which said (translated back to english):

    Lan Manager...  We are here again and we're not very good.

    And now you know "The rest of the story(tm)"

  • Larry Osterman's WebLog

    Why hasn't Larry posted in almost a month?

    • 7 Comments

    Mostly because Larry's been swamped with work :).

     

    I've been heads down working on stuff and it's pretty much monopolized my time for the past month or so.  The good news is that my schedule has relaxed a bit (although I still have what seems to be a never ending stream of threat models to review).

Page 1 of 1 (3 items)