Original article address:
Http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope/6445794#6445794
I have the following code.
int * foo(){ int a = 5; return &a;}int main(){ int* p = foo(); cout << *p; *p = 8; cout << *p;}
And the code is just running with no runtime exceptions!
The output was5 8
The most popular answer
How can it be? Isn' t the memory of a local variable inaccessible outside its function?
You rent a hotel room. you put a book in the top drawer of the bedside table and go to sleep. you check out the next morning, but "forget" to give back your key. you steal the key!
A week later, you return to the hotel, do not check in, sneak into your old room with your stolen key, and look in the drawer. Your book is still there. Astonishing!
How can that be? Isn' t the contents of a hotel room drawer inaccessible if you haven't been rented the room?
Well, obviusly that scenario can happen in the real world no problem. there is no mysterious force that causes your book to disappear when you are no longer authorized to be in the room. nor is there a mysterious force that prevents you from entering
Room with a stolen key.
The hotel management is notRequiredTo remove your book. you didn't make a contract with them that said that if you leave stuff behind, they all shred it for you. if you illegally re-enter your room with a stolen key to get it back, the hotel security
Staff is notRequiredTo catch you sneaking in. you didn't make a contract with them that said "if I try to sneak back into my room later, you are required to stop me. "Rather, you signed a contract with them that said" I promise not to sneak back
Into my room later ", a contract whichYou broke.
In this situationAnything can happen. The book can be there -- you got lucky. someone else's book can be there and yours cocould be in the hotel's furnace. someone cocould be there right when you come in, tearing your book to pieces. the hotel
Cocould have removed the table and book entirely and replaced it with a wardrobe. the entire hotel cocould be just about to be torn down and replaced with a football stadium, and you are going to die in an explosion while you are sneaking around.
You don't know what is going to happen; when you checked out of the hotel and stole a key to illegaly use later, you gave up the right to live in a predictable, safe World because
YouChose to break the rules of the system.
C ++ is not a safe Language. It will cheerfully allow you to break the rules of the system. if you try to do something illegal and foolish like going back into a room you're not authorized to be in and rummaging through a desk that might
Not even be there anymore, C ++ is not going to stop you. safer versions ages than C ++ solve this problem by restricting your power -- by having much stricter control over keys, for example.
Update
Holy Goodness, this answer is getting a lot of attention. (I'm not sure why -- I considered it to be just a "fun" little analogy, but whatever .)
I thought it might be germane to update this a bit with a few more technical thoughts.
Compilers are in the business of generating code which manages the storage of the data manipulated by that program. there are lots of different ways of generating code to manage memory, but over time two basic techniques have become entrenched.
The first is to have some sort of "long lived" storage area where the "Lifetime" of each byte in the storage -- that is, the period of time when it is validly associated with some program variable -- cannot be easily predicted ahead of time. the Compiler
Generates callinto a "heap manager" that knows how to dynamically allocate storage when it is needed and reclaim it when it is no longer needed.
The second is to have some sort of "short lived" storage area where the lifetime of each byte in the storage is well known, and, in particle, lifetimes of storages follow a "nesting" pattern. that is, the allocation of the longest-lived of the short-lived
Variables strictly overlaps the allocations of shorter-lived variables that come after it.
Local variables follow the latter pattern; When a method is entered, its local variables come alive. when that method callanother method, the new method's local variables come alive. they'll be dead before the first method's local variables are dead. the
Relative order of the beginnings and endings of life times of storages associated with local variables can be worked out ahead of time.
For this reason, local variables are usually generated as storage on a "stack" data structure, because a stack has the property that the first thing pushed on it is going to be the last thing popped off.
It's like the hotel decides to only rent out rooms sequentially, and you can't check out until everyone with a room number higher than you has checked out.
So let's think about the stack. in your operating systems you get one stack per thread and the stack is allocated to be a certain fixed size. when you call a method, stuff is pushed onto the stack. if you then pass a pointer to the stack back out of your
Method, as the original poster does here, that's just a pointer to the middle of some entirely valid million-byte memory block. in our analogy, you check out of the hotel; when you do, you just checked out of the highest-numbered occupied room. if no one else
Checks in after you, and you go back to your room illegally, all your stuff is guaranteed to still be there
In this special hotel.
We use stacks for temporary stores because they are really cheap and easy. an Implementation of C ++ is not required to use a stack for storage of locals; it cocould use the heap. it doesn' t, because that wocould make the program slower.
An Implementation of C ++ is not required to leave the garbage you left on the stack untouched so that you can come back for it later illegally; it is perfectly legal for the compiler to generate code that turns back to zero everything in the "room" that
You just vacated. It doesn' t because again, that wocould be expensive.
An Implementation of C ++ is not required to ensure that when the stack logically shrinks, the addresses that used to be valid are still mapped into memory. the implementation is allowed to tell the Operating System "We're re done using this page of stack now.
Until I say otherwise, issue an exception that destroys the process if anyone touches the previusly-valid stack page ". Again, implementations do not actually do that because it is slow and unnecessary.
Instead, implementations let you make mistakes and get away with it. Most of the time. Until one day something truly awful goes wrong and the process explodes.
This is problematic. there are a lot of rules and it is very easy to break them accidentally. I certainly have times. and worse, the problem often only surfaces when memory is detected to be updated upt billions of nanoseconds after the specified uption happened,
When it is very hard to figure out who messed it up.
More memory-safe versions ages solve this problem by restricting your power. in "normal" C # there simply is no way to take the address of a local and return it or store it for later. you can take the address of a local, but the language is cleverly designed
So that it is impossible to use it after the lifetime of the local ends. in order to take the address of a local and pass it back, you have to put the compiler in a special "unsafe" mode,
AndPut the word "unsafe" in your program, to call attention to the fact that you are probably doing something dangerous that cocould be breaking the rules.
For further reading:
- What if C # did allow returning references? Coincidentally that is the subject of today's blog post:
Http://blogs.msdn.com/ B /ericlippert/archive/2011/06/23/ref-returns-and-ref-locals.aspx
- Why do we use stacks to manage memory? Are value types in C # always stored on the stack? How does virtual memory work? And more topics in how the C # Memory Manager works. Examples of these articles are also germane to C ++ programmers:
Http://blogs.msdn.com/ B /ericlippert/archive/tags/memory+management/