|
|
Classification: |
C++ |
Category: |
Memory Management & Cleanup |
Created: |
12/15/2004 |
Modified: |
01/07/2005 |
Number: |
FAQ-1195 |
Platform: |
Not Applicable |
|
Question: Why does TRAP(ing) a 'LC' method cause a panic upon returning ? Is it possible to reference an object on the stack during a leave ?
Answer: Can I TRAP a 'LC' method ?
A 'LC' method/function that pushes objects on the CleanupStack before returning CANNOT be trapped using TRAP or TRAPD - unlike
a 'L;' method that can simply leave. As an example the code snippet below calls a NewLC() method in the intialization method.
The line with the trap will cause a E32USER-CBASE 71 panic if the NewLC method returns normally i.e. it does NOT leave.
void CMyClass::Init() {
TInt err = KErrNone; TAny* pointerToSomething = NULL;
TRAP(err, pointerToSomething = MyObject::NewLC()); // This will cause a panic !
if (err != KErrNone) TRAP(err, SomethingElseL()); // No panics here ! else { err = pointerToSomething->SomeMethod(); CleanupStack::PopAndDestroy(pointerToSomething ); } } Why does TRAP(ing) a 'LC' method cause a panic upon returning ?
The panic happens due to the way trap handling works in Symbian OS in tandem with the CleanupStack framework. FAQ-0185 details some aspect of the exception mechanism. Unlike C++ exceptions Symbian employs a long jump (non-local Goto) which
does not involve the unwinding of the stack (thus deletion of objects on the stack frame does NOT occur). In principle everytime
TRAP(D) is invoked a trap frame (TTrap) is added to mark a point from where execution should continue when an exception is
thrown (User::Leave). The frame not only marks the point of return but the context from which the exception should recover.
The point where a TRAP is set will be different to the place where an exception is raised; hence, the context is used to 'unreel'
(recommence execution) from the execution state at the time of the exception being raised (which could be one or more subroutine
jumps) to where the TRAP was set.
In the absence of C++ exception handling within Symbian OS, the CleanupStack works in conjunction with the TRAP framework
(which includes a trap handler per thread) to provide a means of garbage collecting objects on the heap (and reference objects
on the stack - see below). When a TRAP is used a 'cleanup' level is marked in the cleanup stack as a reference (starting)
point for that TRAP frame. There is a one-to-one relation between a stack frame and a cleanup level. Every TRAP is associated
to one cleanup level. TRAP frames and objects on the cleanup stack are pushed and popped in a LIFO fashion. During an exception,
objects on the cleanup stack are deleted in the last 'cleanup' level (pertaining to the last TRAP frame) before execution
control returns to the last TRAP point. Associating a TRAP frame with a 'cleanup' level ensures that only objects pushed after
the current and before the next TRAP frame are deleted.
Hence the reason for the panic....
In the case when an exception is raised, all objects on the CleanupStack in the current level are destroyed before the context
is reinstated. However, if a leave did not transpire and the 'LC' method returns normally, the exception handler is 'untrapped'
to unmark (disassociate) the current cleanup level and the TRAP frame. The CleanupStack mandates that at this point all objects
should have been popped; thus, the above panic is raised if any objects are found on the current level before unmarking of
the level is done. This is normal behaviour as it is expected that upon normal return all objects should have been accounted
for (i.e. either popped and/or destroyed) in the called method. Note that the same principle applies to a leaving ('L') method.
The above panic is also raised if an object is left on the cleanup stack erroneously. In this case the unmatched push would
be difficult to trace as the panic might appear sometime after the offending method returns.
Is it possible to reference an object on the stack during a leave ? Due to the TRAPing mechanism it is possible to perform operations on objects on the stack, for example using CleanupClosePushL()
in the process of an exception being handled. This works because the objects on the CleanupStack are handled first before
the context is reconfigured. Once the context is changed the stack frame does not reflect the current execution state; hence,
all objects on the stack are lost (cleared). FAQ-0320 explains the cleanup stack and exception handling in more detail. FAQ-0119 draws attention to the pitfalls of nested TRAPs if not used correctly.
|
|
|