Will C reuse the memory of a local block var once

2019-02-27 10:28发布

问题:

(I believe this question is technically distinct from Can a local variable's memory be accessed outside its scope? because it is C instead of C++.)

I know that in C you can put a local variable in a block and it will be scoped to that block:

#include <stdio.h>
int main() {
    {
        int x = 5;
        printf("x = '%d'\n", x);
    }
    // can't see x anymore
}

My question is, is it nonetheless still SAFE to use that memory until the end of the function? Whether it is WISE from a design / coding practices perspective is a separate question, but is it undefined behavior or can I count on that memory staying put? For example:

#include <stdio.h>
int main() {
    int *ptr;

    {
        int x = 5;
        printf("x = '%d'\n", x);

        // hold on to a ptr while we still know the address
        ptr = &x;
    }

    // can't see x anymore, but is this safe?
    printf("still have a ptr! '%d'\n", *ptr);
}

Thanks!

回答1:

The C99, 6.2.4 p2 standard says:

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 reaches the end of its lifetime.



回答2:

Is it nonetheless still SAFE to use that memory until the end of the function?

No, it is not. Once the variable is out of scope, any reference to the memory that it once occupied is undefined behavior.

Here is a short demo with UB happening when the compiler reuses memory allocated inside a block:

int *ptr1, *ptr2;
{
    int x[8];
    scanf("%d", x);
    printf("You entered x=%d\n", x[0]);
    ptr1 = x;
}
{
    int y[8];
    scanf("%d", y);
    printf("You entered y=%d\n", y[0]);
    ptr2 = y;
}
printf("Now x=%d\n", *ptr1); // <<== Undefined behavior!!!
printf("Now y=%d\n", *ptr2); // <<== Undefined behavior!!!

I made an array because the compiler used for the demo chooses to not reuse memory of individual variables and smaller arrays. Once a certain threshold is crossed, however, the memory is reused.

Demo.

This demo shows how the address of int x[8] is reused for int y[8].



回答3:

You cannot safely look at what that pointer points to, once you're outside the block, exactly as you suspect.

The "memory location" that was used for the value of X, of course, lives on, so something is likely to be there. But accessing it has no guaranteed safe result; you're likely to see garbage, and in extreme cases it might even crash the program. (And for some amount of time, you might find that the original value of X is still present! That's a red herring; it doesn't make it OK to use.)



回答4:

It's undefined behavior. It may work on some architectures or operating systems, but don't count on it. An example of where it may work is Linux, with the red zone enabled.