Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding stack-allocated objects deallocation

I'm trying to understand how deallocation of stack-allocated objects behaves. To be precise, I'm trying to find an explanation in the standard (N1570). Consider the following simple function:

void foo(){
    char test[4096];
    test[10] = 0;
}

Here the test array will be deallocated when foo exits. It is easy to see in objdump that test is allocated on the stack. The standard (emphasis mine) states:

An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration, as do some compound literals.

So test has automatic storage duration. We can easily rewrite the function as follows:

void test(){
    char *test= malloc(4096 * sizeof(char));
    test[10] = 0;
    free(test);
}

But we have to deallocate it by ourselves, and yet test still has automatic storage duration.

QUESTION: How the standard specifies that char test[4096] will be deallocated on function exit? The standard does not state that test is allocated on the stack, it is implementation defined.

like image 923
St.Antario Avatar asked Jan 28 '23 03:01

St.Antario


1 Answers

The standard describes the various storage durations at §6.2.4

1 An object has a storage duration that determines its lifetime. There are four storage durations: static, thread, automatic, and allocated. Allocated storage is described in 7.22.3.

2 The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address, and retains its last-stored value throughout its lifetime. If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

6 For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration or compound literal is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.

So you are pretty much correct. It doesn't at all describe when and how storage is deallocated per se. It only specifies when that storage is accessible with well-defined semantics. An implementation need not deallocate the storage of a variable with automatic storage duration right away, you just can't touch it if you want your program to be standard compliant.

For allocated storage the same goes, with the added caveat that you have to explicitly tell the implementation you are done with the storage. But even if you do "free" it, an implementation may hold on to it still for a while longer.

It's possible on paper for a very poor implementation to exist, one which never deallocates memory. But in practice, those are culled naturally because poor implementations of C just become disused by the masses, and abandoned.

like image 182
StoryTeller - Unslander Monica Avatar answered Feb 05 '23 02:02

StoryTeller - Unslander Monica