What is stack unwinding?

C++Stack

C++ Problem Overview


What is stack unwinding? Searched through but couldn't find enlightening answer!

C++ Solutions


Solution 1 - C++

Stack unwinding is usually talked about in connection with exception handling. Here's an example:

void func( int x )
{
    char* pleak = new char[1024]; // might be lost => memory leak
    std::string s( "hello world" ); // will be properly destructed

    if ( x ) throw std::runtime_error( "boom" );

    delete [] pleak; // will only get here if x == 0. if x!=0, throw exception
}

int main()
{
    try
    {
        func( 10 );
    }
    catch ( const std::exception& e )
    {
        return 1;
    }

    return 0;
}

Here memory allocated for pleak will be lost if an exception is thrown, while memory allocated to s will be properly released by std::string destructor in any case. The objects allocated on the stack are "unwound" when the scope is exited (here the scope is of the function func.) This is done by the compiler inserting calls to destructors of automatic (stack) variables.

Now this is a very powerful concept leading to the technique called http://en.wikipedia.org/wiki/RAII">RAII</a>;, that is Resource Acquisition Is Initialization, that helps us manage resources like memory, database connections, open file descriptors, etc. in C++.

Now that allows us to provide http://www.gotw.ca/gotw/056.htm">exception safety guarantees.

Solution 2 - C++

All this relates to C++:

Definition: As you create objects statically (on the stack as opposed to allocating them in the heap memory) and perform function calls, they are "stacked up".

When a scope (anything delimited by { and }) is exited (by using return XXX;, reaching the end of the scope or throwing an exception) everything within that scope is destroyed (destructors are called for everything). This process of destroying local objects and calling destructors is called stack unwinding.

You have the following issues related to stack unwinding:

  1. avoiding memory leaks (anything dynamically allocated that is not managed by a local object and cleaned up in the destructor will be leaked) - see RAII referred to by Nikolai, and the documentation for boost::scoped_ptr or this example of using boost::mutex::scoped_lock.

  2. program consistency: the C++ specifications state that you should never throw an exception before any existing exception has been handled. This means that the stack unwinding process should never throw an exception (either use only code guaranteed not to throw in destructors, or surround everything in destructors with try { and } catch(...) {}).

If any destructor throws an exception during stack unwinding you end up in the land of undefined behavior which could cause your program to terminate unexpectedly (most common behavior) or the universe to end (theoretically possible but has not been observed in practice yet).

Solution 3 - C++

In a general sense, a stack "unwind" is pretty much synonymous with the end of a function call and the subsequent popping of the stack.

However, specifically in the case of C++, stack unwinding has to do with how C++ calls the destructors for the objects allocated since the started of any code block. Objects that were created within the block are deallocated in reverse order of their allocation.

Solution 4 - C++

I don't know if you read this yet, but Wikipedia's article on the call stack has a decent explanation.

Unwinding: >Returning from the called function will pop the top frame off of the stack, perhaps leaving a return value. The more general act of popping one or more frames off the stack to resume execution elsewhere in the program is called stack unwinding and must be performed when non-local control structures are used, such as those used for exception handling. In this case, the stack frame of a function contains one or more entries specifying exception handlers. When an exception is thrown, the stack is unwound until a handler is found that is prepared to handle (catch) the type of the thrown exception. > >Some languages have other control structures that require general unwinding. Pascal allows a global goto statement to transfer control out of a nested function and into a previously invoked outer function. This operation requires the stack to be unwound, removing as many stack frames as necessary to restore the proper context to transfer control to the target statement within the enclosing outer function. Similarly, C has the setjmp and longjmp functions that act as non-local gotos. Common Lisp allows control of what happens when the stack is unwound by using the unwind-protect special operator. > >When applying a continuation, the stack is (logically) unwound and then rewound with the stack of the continuation. This is not the only way to implement continuations; for example, using multiple, explicit stacks, application of a continuation can simply activate its stack and wind a value to be passed. The Scheme programming language allows arbitrary thunks to be executed in specified points on "unwinding" or "rewinding" of the control stack when a continuation is invoked.

Inspection[edit]

Solution 5 - C++

Stack unwinding is a mostly C++ concept, dealing with how stack-allocated objects are destroyed when its scope is exited (either normally, or through an exception).

Say you have this fragment of code:

void hw() {
    string hello("Hello, ");
    string world("world!\n");
    cout << hello << world;
} // at this point, "world" is destroyed, followed by "hello"

Solution 6 - C++

I read a blog post that helped me understand.

> What is stack unwinding? > > In any language that supports recursive functions (ie. pretty much > everything except Fortran 77 and Brainf*ck) the language runtime keeps > a stack of what functions are currently executing. Stack unwinding is > a way of inspecting, and possibly modifying, that stack. > > Why would you want to do that? > > The answer may seem obvious, but there are several related, yet subtly > different, situations where unwinding is useful or necessary: > > 1. As a runtime control-flow mechanism (C++ exceptions, C longjmp(), etc). > 2. In a debugger, to show the user the stack. > 3. In a profiler, to take a sample of the stack. > 4. From the program itself (like from a crash handler to show the stack). > > These have subtly different requirements. > Some of these are performance-critical, some are not. Some require the > ability to reconstruct registers from outer frame, some do not. But > we'll get into all that in a second.

You can find the full post here.

Solution 7 - C++

IMO, the given below diagram in this article beautifully explains the effect of stack unwinding on the route of next instruction (to be executed once an exception is thrown which is uncaught):

enter image description here

In the pic:

  • Top one is a normal call execution (with no exception thrown).
  • Bottom one when an exception is thrown.

In the second case, when an exception occurs, the function call stack is linearly searched for the exception handler. The search ends at the function with exception handler i.e. main() with enclosing try-catch block, but not before removing all the entries before it from the function call stack.

Solution 8 - C++

Everyone has talked about the exception handling in C++. But,I think there is another connotation for stack unwinding and that is related to debugging. A debugger has to do stack unwinding whenever it is supposed to go to a frame previous to the current frame. However, this is sort of virtual unwinding as it needs to rewind when it comes back to current frame. The example for this could be up/down/bt commands in gdb.

Solution 9 - C++

C++ runtime destructs all automatic variables created between between throw & catch. In this simple example below f1() throws and main() catches, in between objects of type B and A are created on the stack in that order. When f1() throws, B and A's destructors are called.

#include <iostream>
using namespace std;

class A
{
    public:
	   ~A() { cout << "A's dtor" << endl; }
};

class B
{
    public:
	   ~B() { cout << "B's dtor" << endl; }
};

void f1()
{
	B b;
	throw (100);
}

void f()
{
	A a;
	f1();
}

int main()
{
	try
	{
        f();
	}
	catch (int num)
	{
        cout << "Caught exception: " << num << endl;
	}
	
	return 0;
}

The output of this program will be

B's dtor
A's dtor

This is because the program's callstack when f1() throws looks like

f1()
f()
main()

So, when f1() is popped, automatic variable b gets destroyed, and then when f() is popped automatic variable a gets destroyed.

Hope this helps, happy coding!

Solution 10 - C++

When an exception is thrown and control passes from a try block to a handler, the C++ run time calls destructors for all automatic objects constructed since the beginning of the try block. This process is called stack unwinding. The automatic objects are destroyed in reverse order of their construction. (Automatic objects are local objects that have been declared auto or register, or not declared static or extern. An automatic object x is deleted whenever the program exits the block in which x is declared.)

If an exception is thrown during construction of an object consisting of subobjects or array elements, destructors are only called for those subobjects or array elements successfully constructed before the exception was thrown. A destructor for a local static object will only be called if the object was successfully constructed.

Solution 11 - C++

In Java stack unwiding or unwounding isn't very important (with garbage collector). In many exception handling papers I saw this concept (stack unwinding), in special those writters deals with exception handling in C or C++. with try catch blocks we shouln't forget: free stack from all objects after local blocks.

Solution 12 - C++

Stack unwinding is the process of removing function entries from the function call stack at runtime. It generally related to exception handling. In C++ when an exception occurs , the function call stack is linearly searched for the exception handler all the entries before the function with exception handlers are removed from the function call stack .

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRajendra UppalView Question on Stackoverflow
Solution 1 - C++Nikolai FetissovView Answer on Stackoverflow
Solution 2 - C++utnapistimView Answer on Stackoverflow
Solution 3 - C++jristaView Answer on Stackoverflow
Solution 4 - C++John WeldonView Answer on Stackoverflow
Solution 5 - C++Chris Jester-YoungView Answer on Stackoverflow
Solution 6 - C++L. LangóView Answer on Stackoverflow
Solution 7 - C++Saurav SahuView Answer on Stackoverflow
Solution 8 - C++bbvView Answer on Stackoverflow
Solution 9 - C++DigitalEyeView Answer on Stackoverflow
Solution 10 - C++MK.View Answer on Stackoverflow
Solution 11 - C++user2568330View Answer on Stackoverflow
Solution 12 - C++Sarath GovindView Answer on Stackoverflow