The ways people mess up IUnknown::QueryInterface, episode 3

Today we'll combine information you already know, some of which I covered in The ways people mess up IUnknown::QueryInterface with additional clues from The layout of a COM object. There's still not enough information for you to solve the problem entirely on your own, but maybe you can demonstrate your nascent psychic debugging powers and solve the problem.

A customer contacted the shell team because their shell extension was causing the shell to crash. Perhaps they were doing something wrong, but they couldn't see what. The crash looked like this:

eax=cccccccc ebx=02b31798 ecx=0008db64 edx=02b26348 esi=001ea7fc edi=02b26348
eip=76381427 esp=0008db28 ebp=0008db30 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
76381427 8b08            mov     ecx,dword ptr [eax]  ds:0023:cccccccc=????????

Your next hint is that the crash takes place while the shell is trying to invoke a COM method.

What you should recognize is that this is either at the fetch of a COM object's vtable or at the fetch of the pointer to the IUnknown::QueryInterface method (which is the first function in the vtable of any COM object).

Either way, we obviously have a bad COM object pointer. The next hint is that the pointer was the result of a call to IUnknown::QueryInterface:

ISomeInterface* psi;
punkObj->QueryInterface(IID_ISomeInterface, (void**)&psi);

If you prefer to speak ATL, it would be something like

CComQIPtr<ISomeInterface> spsi(punkObj);

Either way, the problem is that the punkObj responded to IUnknown::QueryInterface by putting the special debugging value 0xCCCCCCCC into the output pointer rather than following the rules for IUnknown::QueryInterface which require you either to succeed and produce a valid object pointer or to fail and set the output pointer to NULL.

The object in question came from the customer's shell extension. After we pointed out to the customer that their IUnknown::QueryInterface implementation did not adhere to the interface contract, all further communication ceased. We never did get any acknowledgement or even a word of thanks. Maybe they were too embarrassed.

Comments (20)
  1. Ben Voigt [C++ MVP] says:

    So, did the shell team fix their own bug (ignoring the HRESULT from QueryInterface)?‘s_Law

  2. Sunil Joshi says:


    That’s all very well in theory but not so great for the user whose explorer window crashes. I don’t checking the HRESULT is too much to ask for given the other app compact things that Mr Chen has written about (I’m thinking in particular about the one where they corrected for a messed up stack.)

    I would take this all back, of course, if it turns out there are more extensions that return a failing HRESULT but fill *ppv with a genuinely useful pointer (which is really deranged.)

  3. jim says:

    Oh, I can quite easily see somebody (mis)implementing QueryInterface as something like

    void* result;

    // Recklessly fail to initialise result

    if (it’s an interface that I support)


     // Set up result, all happy.


    // Recklessly assume all is well

    return S_OK;

    in which case you’re screwed even if you check the return value–it’ll claim to have given you a usable pointer, but actually return garbage.

    (I don’t see any preview button, so you will have to hope that that was formatted in some sort of sane manner.)

  4. jim says:

    Of course, there should be a

    *ppv = result;

    in there before the return.

  5. porter says:

    All COM methods that have [out] only arguments require the callee to set the output value whether there is an error or not. This is because COM is built on RPC which does not care about what HRESULT means, the output arguments still have to be able to be marshalled.

  6. Ignore HRESULTs at your own peril.  IUnknown::QueryInterface may fail for a number of reasons, not just E_NOINTERFACE.  e.g. if the QI call has to allocate memory (tear off) it can fail even though the object could support the interface.  And then if the interface provided a critical function, you could end up losing user data by treating out of memory the same as E_NOINTERFACE.

    Personally I think that a better contract is that the returned interface pointer is set to NULL with a success HRESULT if the requested interface is not supported.  This way a uniform simple test could be used instead of the more complex testing against E_NOINTERFACE (which in the end leads people to often do neither).

  7. John says:

    The problem is not the contract; the problem is idiots who don’t follow the contract.  You can fix the contract; you can’t fix the idiots.

    Alternatively, you can lead an idiot to a contract but you can’t make him follow it.

  8. Nick says:


    I’ve never programmed with COM at all, but looking at your crash dump summary that 0xcccccccc in eax stood out like a neon signpost.

    Possible false positive? Sure, but an unlikely pattern like that seems like a good starting point.  (Lot more example at

  9. John says:

    Well, yeah Nick. Raymond said as much in his post ("by putting the special debugging value 0xCCCCCCCC into the output pointer"). So we know something is likely uninitialized. This is a bit outside my psychic debugging abilities so I look forward to the answer.

  10. S says:


    You’re allowed to ignore the HRESULT from QueryInterface. The contract says it either succeeds and sets *ppv to a valid interface pointer, or it fails and sets *ppv to NULL. So long as ppv isn’t NULL (in which case you’re stuffed anyway), there is no real need to look at the return value of QueryInterface – all it tells you is whether *ppv will be NULL or not.

  11. Jon Bright says:

    Thanks to this post, I’ve just been through and corrected my QueryInterface implementations, which were setting the output pointer to "this" even if they failed.  The world has been made a little bit better…

  12. Tim Hollebeek says:

    At one point, I was working on a DARPA research project that involved monitoring what was going on inside of Internet Explorer 4.0.  We would call QueryInterface for IUnknown on arbitary objects passing through the scripting API, in order to determine object equality (this was needed for reasons I won’t go into here).  Imagine our surprise when our software crashed … because certain objects inside IE returned E_NOT_SUPPORTED when queried for IUnknown.

  13. Nick says:


    I was suspicious of the 0xcccccccc value in eax before reading any further in Raymond’s post.  As I said, I’m not familiar with COM so I wouldn’t be all the much help in debugging this, but numbers like that are something of a red flag (they jest ain’t natural, ya’see).

    Oh well.

  14. Tim Hollebeek says:

    Anyway, 0xcccccccc is the standard value for uninitialized local variables.  I suspect something like:

    int ret;

    int code = E_NOT_IMPLEMENTED;

    if ( ) {} else if ( ) {} else if ( ) { }

    *outval = ret;

    return code;

  15. Worf says:

    Hrm, and people ignore one of tghe more useful compiler warnings out there? Possible uninitialized variable usage should never occur unless by design, at which point there should be a good comment why (e.g., a bug in Debian’s OpenSSL build where uninitialized mempry was used as a small source of entropy, but caused tools like valgrind/lint to complain, so the packager "fixed" it, but inadvertently introduced a bug that reduced entropy…).

  16. Goran says:

    "Either way, the problem is that the punkObj responded to IUnknown::QueryInterface by putting the special debugging value 0xCCCCCCCC into the output pointer"

    Well, either that, either it was a combination of a debug build and an uninitialized stack variable!

  17. Anonymous Coward says:

    I felt the giggles begin when I saw eax, and by the time I was at ds:0023:cccccccc= there was tea everywhere. I know it’s wrong to laugh at other people’s miseries, but in cases like this I just can’t help it. I hope that doesn’t make me a bad person.

  18. Kevin Eshbach says:

    This reminds me of seeing developers who need to add new functionality to a published interface so instead of creating a new interface they just add the new methods to the end of the existing published interface.

  19. 640k says:

    This reminds me of seeing developers who need to add new functionality to a published interface so instead of creating a new interface they just add the new methods to the end of the existing published interface.

    It’s called inheritance.

  20. s says:

    @Tim Hollebeek

    That’s kind of allowed though – if you’re working on a scripting engine which (say) has great IDispatch support, and you needed to pass a local object through it you can pass an object which only supports IDispatch and ignores the rest of COM, as long as a) you own the scripting engine and you know it will cope and b) you never hand that interface pointer to someone who will assume it supports IUnknown. I know very little about scripting engines, but I don’t recall in my limited jscript experience being told "this object is definitely a COM object and here is an IDispatch you can party on", even though presumably under the hood that is how it works most of the time.

    I’ve definitely written objects  which look enough like a real COM object to satisfy the otherwise COM-to-the-core app architecture – sometimes it is a useful shortcut – but I always owned both ends of the contract.

Comments are closed.

Skip to main content