c++ dangling-pointer local-variables memory-management

Can a local variable’s memory be accessed outside its scope?


I have the following code.

#include <iostream>

int * foo()
    int a = 5;
    return &a;

int main()
    int* p = foo();
    std::cout << *p;
    *p = 8;
    std::cout << *p;

And the code is just running with no runtime exceptions!

The output was 58

How can it be? Isn’t the memory of a local variable inaccessible outside its function?


  • 14

    this won’t even compile as is; if you fix the nonforming business, gcc will still warn address of local variable ‘a’ returned; valgrind shows Invalid write of size 4 [...] Address 0xbefd7114 is just below the stack ptr

    – sehe

    Jun 22, 2011 at 14:34

  • 82

    @Serge: Back in my youth I once worked on some kinda tricky zero-ring code that ran on the Netware operating system that involved cleverly moving around the stack pointer in a way not exactly sanctioned by the operating system. I’d know when I’d made a mistake because often the stack would end up overlapping the screen memory and I could just watch the bytes get written right onto the display. You can’t get away with that sort of thing these days.

    Jun 23, 2011 at 4:23

  • 23

    lol. I needed to read the question and some answers before I even understood where the problem is. Is that actually a question about variable’s access scope? You don’t even use ‘a’ outside your function. And that is all there is to it. Throwing around some memory references is a totally different topic from variable scope.

    Jun 23, 2011 at 6:23

  • 10

    Dupe answer doesn’t mean dupe question. A lot of the dupe questions that people proposed here are completely different questions that happen to refer to the same underlying symptom… but the questioner has know way of knowing that so they should remain open. I closed an older dupe and merged it into this question which should stay open because it has a very good answer.

    Jun 23, 2011 at 14:36

  • 16

    @Joel: If the answer here is good, it should be merged into older questions, of which this is a dupe, not the other way around. And this question is indeed a dupe of the other questions proposed here and then some (even though some of the proposed are a better fit than others). Note that I think Eric’s answer is good. (In fact, I flagged this question for merging the answers into one of the older questions in order to salvage the older questions.)

    – sbi

    Jun 23, 2011 at 15:20



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? Aren’t the contents of a hotel room drawer inaccessible if you haven’t rented the room?

Well, obviously 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 a room with a stolen key.

The hotel management is not required to remove your book. You didn’t make a contract with them that said that if you leave stuff behind, they’ll shred it for you. If you illegally re-enter your room with a stolen key to get it back, the hotel security staff is not required to 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 which you broke.

In this situation anything can happen. The book can be there — you got lucky. Someone else’s book can be there and yours could be in the hotel’s furnace. Someone could be there right when you come in, tearing your book to pieces. The hotel could have removed the table and book entirely and replaced it with a wardrobe. The entire hotel could 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 illegally use later, you gave up the right to live in a predictable, safe world because you chose 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 languages than C++ solve this problem by restricting your power — by having much stricter control over keys, for example.


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 calls into 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 method is to have a “short-lived” storage area where the lifetime of each byte is well known. Here, the lifetimes follow a “nesting” pattern. The longest-lived of these short-lived variables will be allocated before any other short-lived variables, and will be freed last. Shorter-lived variables will be allocated after the longest-lived ones, and will be freed before them. The lifetime of these shorter-lived variables is “nested” within the lifetime of longer-lived ones.

Local variables follow the latter pattern; when a method is entered, its local variables come alive. When that method calls another 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 lifetimes 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 many 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 particular 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 could use the heap. It doesn’t, because that would 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 would 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 done using this page of stack now. Until I say otherwise, issue an exception that destroys the process if anyone touches the previously-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 many times. And worse, the problem often only surfaces when memory is detected to be corrupt billions of nanoseconds after the corruption happened, when it is very hard to figure out who messed it up.

More memory-safe languages 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, and put the word “unsafe” in your program, to call attention to the fact that you are probably doing something dangerous that could be breaking the rules.

For further reading:


  • 61

    @muntoo: Unfortunately it’s not like the operating system sounds a warning siren before it decommits or deallocates a page of virtual memory. If you’re mucking around with that memory when you don’t own it anymore the operating system is perfectly within its rights to take down the entire process when you touch a deallocated page. Boom!

    Jun 23, 2011 at 3:41

  • 87

    @Kyle: Only safe hotels do that. The unsafe hotels get measurable profit gains from not having to waste time on programming keys.

    Jun 23, 2011 at 5:35

  • 516

    @cyberguijarro: That C++ is not memory safe is simply a fact. It’s not “bashing” anything. Had I said, for example, “C++ is a horrid mishmash of under-specified, overly-complex features piled on top of a brittle, dangerous memory model and I am thankful every day I no longer work in it for my own sanity”, that would be bashing C++. Pointing out that it’s not memory safe is explaining why the original poster is seeing this issue; it’s answering the question, not editorializing.

    Jun 23, 2011 at 7:27

  • 57

    Strictly speaking the analogy should mention that the receptionist at the hotel was quite happy for you to take the key with you. “Oh, do you mind if I take this key with me?” “Go ahead. Why would I care? I only work here”. It doesn’t become illegal until you try to use it.

    Jun 23, 2011 at 12:24

  • 150

    Please, please at least consider writing a book one day. I would buy it even if it was just a collection of revised and expanded blog posts, and I’m sure so would a lot of people. But a book with your original thoughts on various programming-related matters would be a great read. I know that it’s incredible hard to find the time for it, but please consider writing one.

    – Dyppl

    Jun 24, 2011 at 6:43


What you’re doing here is simply reading and writing to memory that used to be the address of a. Now that you’re outside of foo, it’s just a pointer to some random memory area. It just so happens that in your example, that memory area does exist and nothing else is using it at the moment. You don’t break anything by continuing to use it, and nothing else has overwritten it yet. Therefore, the 5 is still there. In a real program, that memory would be re-used almost immediately and you’d break something by doing this (though the symptoms may not appear until much later!)

When you return from foo, you tell the OS that you’re no longer using that memory and it can be reassigned to something else. If you’re lucky and it never does get reassigned, and the OS doesn’t catch you using it again, then you’ll get away with the lie. Chances are though you’ll end up writing over whatever else ends up with that address.

Now if you’re wondering why the compiler doesn’t complain, it’s probably because foo got eliminated by optimization. It usually will warn you about this sort of thing. C assumes you know what you’re doing though, and technically you haven’t violated scope here (there’s no reference to a itself outside of foo), only memory access rules, which only triggers a warning rather than an error.

In short: this won’t usually work, but sometimes will by chance.



    Because the storage space wasn’t stomped on just yet. Don’t count on that behavior.


    • 2

      Man, that was the longest wait for a comment since, “What is truth? said jesting Pilate.” Maybe it was a Gideon’s Bible in that hotel drawer. And what happened to them, anyway? Notice they are no longer present, in London at least. I guess that under the Equalities legislation, you would need a library of religious tracts.

      – Rob Kent

      Jul 16, 2015 at 16:47

    • I could have sworn that I wrote that long ago, but it popped up recently and found my response wasn’t there. Now I have to go figure out your allusions above as I expect I’ll be amused when I do >.<

      – msw

      Jul 17, 2015 at 3:17

    • 2

      Haha. Francis Bacon, one of Britain’s greatest essayists, whom some people suspect wrote Shakespeare’s plays, because they can’t accept that a grammar school kid from the country, son of a glover, could be a genius. Such is the English class system. Jesus said, ‘I am the Truth’.

      – Rob Kent

      Jul 17, 2015 at 11:00