Why should I use static_cast?

I recently had the dubious pleasure of debugging a User 42 Panic on a piece of Symbian code that was given to me by another company. You always need to make sure you understand what the system is telling you, so I went straight to the documentation:

User 42: This panic is raised by a number of RHeap member functions, AllocLen(), Free(), FreeZ(), ReAlloc(), ReAllocL(), Adjust() and AdjustL() when a pointer passed to these functions does not point to a valid cell.

Hmmm. That didn't really give me many clues. Well, I needed to figure out how to reproduce the bug anyway. That was relatively easy, I could reproduce it with a User::Leave(). The leave was being trapped, and the debugger showed the panic was being issued between the Leave and the TRAP, so that pointed to a problem on the CleanupStack (which agreed with what the documentation said). Isolating the problem even further showed that I could reproduce the problem by doing this:

    CItemBase* item = (CItemBase*)decoder->ReadItemLC(); 
    CleanupStack::PopAndDestroy(item);

For reference, ReadItemLC() constructed an MDecodable, and the inheritance hierarchy looked like:

MultipleInheritance

Ignoring the fact that a function called ReadItemLC() should return a CItemBase*, not an MDecodable*, the problem here is that in that inheritance hierarchy, both CItemBase and MDecodable have their own data (MDecodable has a vtable pointer, even though it's an abstract class). Consequently when you cast a pointer from an MDecodable* to a CItemBase* you get a different pointer value. Try the attached code on any system for a demonstration of the problem.

However, in the code sample above, the CItemBase class had not been fully defined; we had simply forwarded-declared CItemBase. That meant the compiler couldn't do the necessary arithmetic (subtract 4) to convert an MDecodable* to a CItemBase* - because it didn't know whether they were actually part of the same inheritance tree, or completely dissociated types. So it did the equivalent of a reinterpret_cast.

When I changed the code to do the correct C++ style cast:

    CItemBase* item = static_cast<CItemBase*>(decoder->ReadItemLC()); 
    CleanupStack::PopAndDestroy(item);

It promptly failed to compile, because CItemBase hadn't been fully defined. Adding

#include "ItemBase.h"

at the top of the file fixed the compile - and fixed my User 42 Panic as well.

Lesson: next time I get code from another source, check the casting is done properly.

Ben Blaukopf
in Technical

Airsource design and develop apps for ourselves and for our clients. We help people like you to turn concepts into reality, taking ideas from initial design, development and ongoing maintenance and support.

Contact us today to find out how we can help you build and maintain your app.