Question

For straight C and GCC, why doesn't the pointed-to string get corrupted here?

#include <stdio.h>

int main(int argc, char *argv[])
{
    char* str_ptr = NULL; 

    {
        //local to this scope-block
        char str[4]={0};
        sprintf(str, "AGH"); 

        str_ptr = str;
    }

    printf("str_ptr: %s\n", str_ptr);

    getchar();
    return 0;
}

|----OUTPUT-----|

str_ptr: AGH

|--------------------|

Here's a link to the above code compiled and executed using an online compiler.

I understand that if str was a string literal, str would be stored in the bss ( essentially as a static ), but sprintf(ing) to a stack-allocated buffer, I thought the string buffer would be purely stack-based ( and thus the address meaningless after leaving the scope block )? I understand that it may take additional stack allocations to over-write the memory at the given address, but even using a recursive function until a stack-overflow occurred, I was unable to corrupt the string pointed to by str_ptr.

FYI I am doing my testing in a VS2008 C project, although GCC seems to exhibit the same behavior.

Was it helpful?

Solution 2

Most likely the compiler does some sort of simple optimizations resulting in the string still being in the same place on the stack. In other words, the compiler allows the stack to grow to store 'str'. But it doesn't shrink the stack in the scope of main, because it is not required to do so.

If you really want to see the result of saving the address of variables on the stack, call a function.

#include <stdio.h>

char * str_ptr = NULL;
void onstack(void)
{
    char str[4] = {0};
    sprintf(str,"AGH");
    str_ptr = str;
}

int main(int argc, char *argv[])
{  

    onstack();
    int x = 0x61626364;
    printf("str_ptr: %s\n", str_ptr);
    printf("x:%i\n",x);
    getchar();
    return 0;
}

With gcc -O0 -std=c99 strcorrupt.c I get random output on the first printf. It will vary from machine to machine and architecture to architecture.

OTHER TIPS

While nasal lizards are a popular part of C folklore, code whose behaviour is undefined can actually exhibit any behaviour at all, including magically resuscitating variables whose lifetime has expired. The fact that code with undefined behaviour can appear to "work" should neither be surprising nor an excuse to neglect correcting it. Generally, unless you're in the business of writing compilers, it's not very useful to examine the precise nature of undefined behaviour in any given environment, especially as it might be different after you blink.

In this particular case, the explanation is simple, but it's still undefined behaviour, so the following explanation cannot be relied upon at all. It might at any time be replaced with reptilian emissions.

Generally speaking, C compilers will make each function's stack frame a fixed size, rather than expanding and contracting as control flow enters and leaves internal blocks. Unless called functions are inlined, their stack frames will not overlap with the stack frame of the caller.

So, in certain C compilers with certain sets of compile options and except for particular phases of the moon, the character array str will not be overwritten by the call to printf, even though the variable's lifetime has expired.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top