Why do I get different results when I dereference a pointer after freeing it?

試著忘記壹切 提交于 2019-11-27 09:50:19

free() (and malloc()) are not from gcc. They come from the C library, which on Debian is usually glibc. So, what you are seeing is glibc's behavior, not gcc's (and would change with a different C library, or a different version of the C library).

I particular, after you use free() you are releasing the memory block malloc() gave you. It's not yours anymore. Since it is not supposed to be used anymore, the memory manager within glibc is free to do whatever it wants with the memory block, including using parts of it as its own memory structures (which is probably why you are seeing its contents change; they have been overwritten with bookkeeping information, probaly pointers to other blocks or counters of some sort).

There are other things that can happen; in particular, if the size of your allocation was large enough, glibc can ask the kernel for a separate memory block for it (with mmap() or similar calls), and release it back to the kernel during the free(). In that case, your program would crash. This can in theory also happen in some circunstances even with small allocations (glibc can grow/shrink the heap).

It is undefined behaviour, so it is an error to deference freed pointer as strange things may (and will) happen.

free() doesn't change the value of the pointer so it keeps pointing to the heap in the process address space - that's why you don't get segfault, however it is not specified and in theory on some platforms you can get segfault when you try to dereference pointer immediately after freeing.

To prevent this it is a good habit to assign pointer to NULL after freeing so it will fail in predictable way - segfault.

Please note that on some OSes (HP-UX, may be some others as well) it is allowed to dereference NULL pointer, just to prevent segfault (and thus hiding problems). I find it rather stupid as it makes things much more difficult to diagnose, although I don't know the full story behind this.

This is probably not the answer you are looking for, but I'll give it a try anyway:

Since you're playing with undefined behaviour that you should never depend on in any way, shape or form, what good does it do to know how exactly one given implementation handles that?

Since gcc is free to change that handling at any given time, between versions, architectures or depending on the position and brightness of the moon, there's no use whatsoever in knowing how it handles it right now. At least not to the developer that uses gcc.

*(p+4) is 8 and *x is 0. Why does this happen? If *(p+4) is 8, shouldn't *x be 6, since the first element of the x-array is 6?

One possible explanation for this would be that printf("...%i..."...) might internally use malloc to allocate a temporary buffer for it's string interpolation. That would overwrite the contents of both arrays after the first output.

Generally, I would consider it an error if a program relies on the value of a pointer after it has been freed. I would even say that it's a very bad code smell if it keeps the value of a pointer after it has been freed (instead of letting it go out of scope or overwriting it with NULL). Even if it works under very special circumstances (single-threaded code with a specific heap manager).

Once you free the dynamic-memory variable, it is not yours. The memory manager is free to do what ever it sees better with that piece of memory you where pointing to. The compiler doesn't do anything as far as I know with the freed blocks of memory, because it is a function and not defined by the language. Even if it is defined by the languages, the compiler just inserts calls to the underlying OS functions.

Just wanna say, It is undefined by the language, So you have to check your OS and watch that piece of memory after freeing it. The behavior maybe random, because sometimes other programs ask for memory, sometimes not!

by the way, It is different on my machine, the value changes for both pointers.

Although the behavior you're seeing seems to be consistent, it is not guaranteed to be so. Unforeseen circumstances may causes this behavior to change (let alone the fact that this is completely implemetnatation dependent).

Specifically, in your example you free() the array and then get the old content when you access the array. If you'll have additional malloc() calls after the free() - chances are that the old contents will be lost.

Even if the memory is freed, it is not necessarily reused for some other purpose. Old pointers to your process memory are still valid pointers (though to unallocated memory) so you do not get segmentation faults either.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!