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:
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
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
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
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.