-1

in school the teacher told me that when the call to a function reaches an end everything declared inside the function's block will be erased. But I wrote the following code:

int * secret()
{
    int arr[10]={0};
    arr[0]=9999;
    return arr;
}

int main() {
    printf("%d",secret()[0]);
    return 0;
}

and the output was 9999 which doesn't suit what I was taught.

  • What are you trying to do? –  Mar 04 '20 at 19:34
  • 1
    If the teacher said everything is erased after a function call, the teacher is wrong. While a block is executing, memory for automatic objects defined inside it is **reserved**. That just means there is a rule that the memory may be used for the objects and should not be used for anything else. When execution of the block ends, the memory is **not** reserved. That means there is no rule about using it only for the objects anymore. It does not mean the memory is erased. – Eric Postpischil Mar 04 '20 at 19:35
  • Does this answer your question? [Can a local variable's memory be accessed outside its scope?](https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope) – Yakov Galka Mar 04 '20 at 19:57
  • @ybungalobill Pedantically, that's a C++ question, and this one is C. – Andrew Henle Mar 04 '20 at 19:58

3 Answers3

3

in school the teacher told me that when the call to a function reaches an end everything declared inside the function's block will be erased.

That is a misleading characterization. If your instructor used that specific wording then they did you a disservice. It is not altogether wrong, though, depending on how one interprets it.

What the language specification says is that the lifetime of an object declared, without a storage-class specifier, inside a block (such as the block serving as the function body in a function definition) ends when execution of the innermost containing block ends. You might characterize that as such objects being "erased" in the sense of erasure from existence, but not in the sense of having their contents cleared.

the output was 9999 which doesn't suit what I was taught.

Trying to be as charitable towards the instructor as possible, I do suggest considering that you may have misunderstood what they were trying to tell you.

In any event, attempting to access an object whose lifetime has ended produces undefined behavior. Moreover, when an object's lifetime ends, the values of any pointers to that object become indeterminate. This means that your program's output does not, indeed cannot, contradict what the language specification says about the situation, because the program output is undefined. Any output or none would be equally consistent with C language semantics. If we suppose that your instructor was trying to convey a characterization consistent with the specification, then they are not contradicted either.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
2

In your example, the local variable "arr" gets allocated on the stack. When you return from secret(), the program releases that portion of the stack for use by the next function that gets called, but the pointer you returned is still pointing to that memory location. It still exists as it was until another function comes along and uses that portion of the stack.

Your teacher was correct if you assume they meant that the memory should not be used after returning, but specifically, the stack is not erased as part of the return. This is because by definition the local variables are no longer in scope, and cannot be expected to be in any particular state. There is no reason to use processor cycles to erase it.

The C language requires the designer to manage their use of pointers, which can be both useful and terrible. It gives the designer a lot of freedom, but it is totally up to the designer to know what is on the other end of that pointer and what types of operations they should being doing with it.

rallen911
  • 148
  • 9
0

In most implementations function epilogue just changes the stack pointer but does not purge the actual data. If you need to purge the data you need to do it yourself.

void foo()
{
    char verySecret[5000];
    char verySecret2[5000];
    char verySecret4[5000];

    /* do something */

    /* now purge the data */
    purge(verySecret,0, sizeof(verySecret));
    purge(verySecret2,0, sizeof(verySecret2));
    purge(verySecret4,0, sizeof(verySecret4));
}

0___________
  • 60,014
  • 4
  • 34
  • 74
  • 1
    Calls to `memset` are subject to optimization by the compiler, so the `memset` calls shown in this answer may be removed during compilation and result in no object code at all—the memory will not be erased. There is a special call, `memset_s`, that cannot be optimized away and that guarantees the setting occurs, per C 2018 K.3.7.4.1 4: “Unlike `memset`, any call to the `memset_s` function shall be evaluated strictly according to the rules of the abstract machine as described in (5.1.2.3).” Please never write any code that requires this security without studying the required semantics. – Eric Postpischil Mar 04 '20 at 19:29
  • FYI, I have not voted on this yet and will not be able to reverse the vote if edits are made. – Eric Postpischil Mar 04 '20 at 19:30
  • @EricPostpischil usual nitpick. It only for the illustration purposes only. – 0___________ Mar 04 '20 at 19:30