5

I don't really understand why are those pointer accessible ... any help appreciated

#include <iostream>

class Wicked{
public:
    Wicked() {};
    virtual ~Wicked() {};

    int a;
    int b;
};


class Test
{
public:
    Test() {};
    virtual ~Test() {};

    int c;

    Wicked * TestFunc()
    {
        Wicked * z;
        c = 9;
        z = new Wicked;
        z->a = 1;
        z->b = 5;
        return z;
    };
};

int main()
{
    Wicked *z;

    Test *t = new Test();
    z = t->TestFunc();

    delete z;
    delete t;

    // why can I set 'z' when pointer is already destroyed?
    z->a = 10;

    // why does z->a print 10?
    std::cout << z->a << std::endl;

    // why does t->c exist and print correct value?
    std::cout << t->c << std::endl;

    //------------------------------------------------------

    int * p = new int;
    *p = 4;

    // this prints '4' as expected
    std::cout << *p << std::endl;

    delete p;

    // this prints memory address as expected
    std::cout << *p << std::endl;

    return 0;
}
ildjarn
  • 62,044
  • 9
  • 127
  • 211
user1003948
  • 63
  • 1
  • 3
  • 1
    I don't really understand what is the question. – Tomas Oct 19 '11 at 20:11
  • Unless you rephrase your question, it's my guess it's going to be closed very soon. – xtofl Oct 19 '11 at 20:12
  • after 'z' and 't' pointers are deleted they still print value – user1003948 Oct 19 '11 at 20:14
  • 2
    OP is asking how come after deleting the pointer he gets the old values i.e. the memory is accesible.I don't see a problem with the question – Cratylus Oct 19 '11 at 20:15
  • 2
    possible duplicate of [C++ delete - It deletes my objects but I can still access the data?](http://stackoverflow.com/questions/1930459/c-delete-it-deletes-my-objects-but-i-can-still-access-the-data) – Raymond Chen Oct 19 '11 at 20:21
  • That's quite normal behaviour, isn't it? `delete` operator just frees the memory, but the pointer itself and the memory will remain the same - why should it change? – Tomas Oct 19 '11 at 20:27

6 Answers6

11

Deleting a pointer doesn't zero out any memory because to do so would take CPU cycles and that's not what C++ is about. What you have there is a dangling pointer, and potentially a subtle error. Code like this can sometimes work for years only to crash at some point in the future when some minor change is made somewhere else in the program.

This is a good reason why you should NULL out pointers when you've deleted the memory they point to, that way you'll get an immediate error if you try to dereference the pointer. It's also sometimes a good idea to clear the memory pointed to using a function like memset(). This is particularly true if the memory pointed to contains something confidential (e.g. a plaintext password) which you don't want other, possibly user facing, parts of your program from having access to.

Benj
  • 31,668
  • 17
  • 78
  • 127
  • 2
    NULL'ing the pointer can lead to other types of error being hidden (potentially for long periods). Best to just use smart pointers and not even get into this situation. Also there is no guarantee that de-referencing a NULL pointer will generate an error (any more than other locations) best not to rely on this to detect errors. – Martin York Oct 19 '11 at 20:50
  • Dereferencing a NULL pointer is undefined behavior and so yes I guess it could do anything, but have you ever known an implmentation which won't perform an immediate segmentation fault? I don't think I've ever seen this. Also much as I love smart pointers, some of these can have their pitfalls as well. Circular reference issues with smart_ptr for example can be a nightmare to debug. Although I grant you, uniq_ptr is reasonably fail safe if it's suitable for your usage. – Benj Oct 19 '11 at 21:38
  • Yes several. There are actually several questions on SO that ask "why is it not crashing when I de-reference NULL". [how-can-dereferencing-a-null-pointer-in-c-not-crash-a-program](http://stackoverflow.com/questions/1334929/how-can-dereferencing-a-null-pointer-in-c-not-crash-a-program) – Martin York Oct 19 '11 at 21:41
  • I guess you didn't actually read that question you linked to, the OP says in his "solution" section that "The pointer in question is not NULL", it turned out that he was expecting the delete to NULL the pointer. – Benj Oct 19 '11 at 21:47
  • 1
    Opps. You are write I did not read it I just assumed people were smart enough to write a good title. I suppose people are stupider than I like to believe (including myself). – Martin York Oct 19 '11 at 23:28
  • Anyay does not change anything. yes I have worked on platfroms were it does not crash. Worse I have worked on platforms where the behavior changes with optimization level and even worse were the the development machines had one behavior and the client machines had a completely different behavior. The point being relying on undefined beahvior may work now it may work next year but eventually it will burn you at the most inconvenient point. Relying on for anything including debugging is just asking for trouble. – Martin York Oct 19 '11 at 23:30
  • Interesting, I've not worked on many platforms so perhaps I'm yet to come accross this issue. Having said that, I'm going to continue to NULL my pointers. The way I see it, if you're attempting to use a pointer which points to deleted memory you've already got a bug. If you've NULLed the pointer, you are more likely to find that bug... even if on certain freaky platforms you don't see it. It's not relying on undefined behavior as I see it (since you're not intending to deref the NULL), it's a question of the lesser of two evils if/when you do make a mistake. – Benj Oct 20 '11 at 08:20
  • If you NULL the pointer you are less likely to find bugs as you are hiding other potential logical errors in your code. Explained well here: http://stackoverflow.com/questions/1025589/setting-variable-to-null-after-free/1879469#1879469 – Martin York Oct 20 '11 at 08:23
  • Hmm, it would be ridiculous to use argument popularity as any kind of justification but interesting that this answer got 12 upvotes, but the answer above got 75 from an equaly notable stack overflower proposing the "you should set to NULL" argument. – Benj Oct 20 '11 at 09:01
  • You could (but there are lots of questions that have mindless up votes Does this really deserve 153 (http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier/228797#228797) compared to the next one at 33). The 75 up votes has the same argument as you. The one pointed out has a good explanation of why the conjecture is false. It is worth a read and explains my side better than I can. I have already pointed out why your fails. This just provides a more detailed explanation – Martin York Oct 20 '11 at 09:11
  • Interesting, here's a program which uses mmap to deliberately cause a NULL deref not to crash: http://blogs.oracle.com/ksplice/entry/much_ado_about_null_an1 – Benj Oct 20 '11 at 09:37
  • Ok I've just tried this on the platform which I use, on win32 the NULL page in the address space cannot be mapped by VirtualAlloc meaning that I don't believe you could even write a program that wouldn't crash when you attempted to dereference a pointer into the NULL page of the virtual address space. Any attempt to access that memory (which is specifically protected by the OS) will cause an access violation and will crash your program. I suspect your argument that NULL pointer deferences sometimes don't crash would only hold true on older non-virtual memory OSes... – Benj Oct 20 '11 at 09:55
  • Or newer ones that have not been invented, Or non windows/Linux boxes (still plenty of big mettle around), or on platforms that do not have an OS (such as devices/system on chip) What about mobile phones have you checked those (lots of variation there). Games consoles (and related hardware (does the kennect hardware run an OS? Does it run code?) What about non von-Neuman architectures. :-) Limiting yourself to what you use everyday is going to leave a lot of hardware untested. If all I have are apples that is the NOT the only fruit. – Martin York Oct 20 '11 at 10:02
  • Ok sure, I'm willing to accept this. But for me as a normal win32 programmer who's always going to be working on applications sitting on top of protected virtual memory, setting pointers to NULL does make sense. (You're about to tell me that I shouldn't assume that someone isn't going to stick my code in a kernel driver or something aren't you) ;-) – Benj Oct 20 '11 at 10:05
  • On Linux (with a bit of work (as the default makes sure it does not happen). You can map page 0 (though you have to modify some of the system settings)). But rarely does your code run in isolation (or without the possibility of melisios or inept maintenance). – Martin York Oct 20 '11 at 10:07
  • Yes, I saw that, it looks like if you specify the right flags mmap() will happily map the NULL page into your address space. However, I'm not sure I'd worry about this just from the point of view that setting pointers to NULL helps you catch bugs. – Benj Oct 20 '11 at 10:11
  • I am still convinced that even on Windows the extra protection proves is in effect non existent. As it hides other errors. By hiding the other errors you are less likely to find them in testing and thus the problem is more likely to show in production. I would like the application to crash in testing not in production. – Martin York Oct 20 '11 at 10:11
  • How do access violations hide errors? Surely they just crash your program, help you fix your bug, and then later your code would even run flawlessly on some other system where *NULL wouldn't crash. No? – Benj Oct 20 '11 at 10:13
  • Andreys description is better than mine (http://stackoverflow.com/questions/1025589/setting-variable-to-null-after-free/1879469#1879469). If you get in bad habits on Windows then you will cause havoc when you move to real computers (Jest). Don't rely on things that may not happen. – Martin York Oct 20 '11 at 10:14
  • Actually, the central thesis of his argument is that you might have some other pointer which is not set to NULL which you use to access the same deleted memory. Sure, this is a different kind of bug where setting to NULL won't help you. But setting to NULL in no way hides that kind of error, it just protects you from the first type of error. His argument is.... wrong. – Benj Oct 20 '11 at 10:18
  • That's his argument for why setting it to NULL is a waste of time. But setting it to NULL also hides the double de-reference problem. Which can be potentially be detected (in debug mode at least). – Martin York Oct 20 '11 at 10:20
  • By double dereferencing do you mean double free? I can kind of see this, if you call free() on a NULL pointer it will be ignored wheras if you didn't null the pointer it may or may not crash depending on the status of the memory pointed to. I guess this could hide a bug... (although it's likely to be a perminently symptomless bug) but I still think setting pointers to NULL is justified for the reasons I said before. It's going to help you more than it hinders you... on a modern OS.... with the caveats stated. – Benj Oct 20 '11 at 10:30
  • I disagree. I think it hides more problems than it help prevent. Mainly because I agree with Andreys that it prevents none. – Martin York Oct 20 '11 at 10:31
  • Thinking about it, calling free(NULL) should really crash... that would be more helpful and would silence that particular argument. – Benj Oct 20 '11 at 10:33
  • Fortunately/Unfortunately. free() accepts NULL nowadays (technically it always has but there used to be many implementations that did not handle it correctly). That is a different argument that was resolved into the current form many years ago and all modern systems handle it correctly now. – Martin York Oct 20 '11 at 10:34
  • Well it's been an interesting discussion, thanks. I'm going to carry on NULLing my pointers but I will continue to mull ;-) – Benj Oct 20 '11 at 10:35
10

That's undefined behaviour. Anything can happen.You were lucky this time. Or perhaps unlucky since it would be preferable to get a runtime error! Next time round maybe you'll get a runtime error.

It's not really very useful to reason about why you see a particular manifestation of undefined behaviour. It's best to stick to the well-defined behaviour about which you can reason.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
6

C++ won't stop you from writing to an arbitrary location in memory. When you allocate memory with new or malloc, C++ finds some unused space in memory, marks it as allocated (so that it doesn't accidentally get handed out again), and gives you its address.

Once you delete that memory however, C++ marks it as free and may hand it out to anyone that asks for it. You can still write to it and read from it, but at this point, someone else might be using it. When you write to that place in memory, you may be overwriting some value you have allocated elsewhere.

Jack Edmonds
  • 31,931
  • 18
  • 65
  • 77
5

Here

// why can I set 'z' when pointer is already destroyed?
z->a = 10;

z still points at a memory location.
But it no longer blongs to you. You have passed it to delete and said take care of this pointer. What it does is no longer your concern. Its like when you sell your car; it still exists but its not yours so opening the door and looking in may be possible, but it may result in the police arresting you.

Same with deleted pointers the memory exists but does not belong to you.
If you look inside it may work, but it may also cause a segmentation fault as the library has flushed the page (you never know).

Martin York
  • 257,169
  • 86
  • 333
  • 562
5

delete z; just deallocates the memory z was pointing to, it does not destroy the pointer itself.

So z becomes a wild pointer.

Dennis
  • 14,264
  • 2
  • 48
  • 57
3

Because deleting a block of memory does not zero the value of all pointers that point to it. Deleting memory merely makes a note that the memory is available to be allocated for some other purpose. Until that happens, the memory may appear to be intact -- but you can't count on it, and on some compiler/runtime/architecture combinations, your program will behave differently -- it may even crash.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186