3

The program will run normally when I try to visit an address which is already freed. Is there some goods to avoid? like some function named have_alloca(void *p) can return whether p is a valid address.
I know that valgrind with tool=memcheck can do that. But I want to know if I can avoid it from code.
here is a simple example:

#include <stdlib.h>

int main(int argc, char *argv[])
{
    int *p = malloc(sizeof(int) * 10);
    free(p);
    *(p + 1) = 100;

    return 0;
}

Why I can visit a invalid address? and the program can compile and run without any warns. BTW: Linux.

madper
  • 806
  • 1
  • 10
  • 25
  • What does this have to do with linux? – ApproachingDarknessFish Dec 29 '12 at 05:42
  • @ValekHalfHeart: not a lot, but if there was a solution that was only applicable to Windows (or Solaris, or Mac OS X, or FreeBSD, or ...), it would not have helped [madper](http://stackoverflow.com/users/988680/madper), and if there was a solution that only applied to Linux, then that would have been helpful. As it is, there isn't a general purpose solution on any platform. – Jonathan Leffler Dec 29 '12 at 05:54
  • Here is some explanation on [*why* the access might work (sometimes)](http://stackoverflow.com/a/6445794/597607) – Bo Persson Dec 29 '12 at 09:31

4 Answers4

11

No, You will have to take care of this yourself.
Technically, writing to an memory location that does not belong to you is Undefined Behavior from the perspective of the language standard.

The languages C and C++ provide you the flexibility to reach addresses of variables and play around with them at the expense that it is your responsibility that those addresses contain valid values owned by your variable/object.

The rationale is:

"With greater power comes greater responsibility"

So the responsibility is yours to take.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
8

p is like a normal variable

the call of function free(p) just release the memories that we allocated, but p still holds the address value. Unless you reset it by yourself:

p = NULL;

so keep the following tips in mind:

  1. every time before using a pointer, check if it is a NULL pointer or not.
  2. every time after releasing memories, set NULL to the pointer.
Yuankun
  • 6,875
  • 3
  • 32
  • 34
  • It's really a good way. But, If I have two or more pointer point to a same area. Then, I free it and set one pointer to `NULL`. It still can't avoid I visiting it by other pointer. remember all of the points to the area is real hard. – madper Dec 29 '12 at 06:01
  • it's your responsibility to maintain the pointers.So, try to use a clean and simple way to write your codes. – Yuankun Dec 29 '12 at 06:04
  • @madper Now you understood the benefit of a garbage collector which takes this responsibility off of you. Unfortnuately C does not provide such a thing. I would also encourage you to accept this answer instead of the one currently accepted as Vincent describes good practice here. THe other answer lacks of that. – junix Jan 25 '13 at 15:26
2
  • Assign NULL to pointer after freeing it.
  • Check for not NULL before accessing.
Adeel Ahmed
  • 1,591
  • 8
  • 10
1

In addition to the other replies, you could consider using Boehm's conservative garbage collector, then you would use GC_mallocinstead of malloc and you won't do any free (even if, when absolutely certain that a memory zone becomes useless and unreachable, you could explicitly GC_free it).

But the point of C is that you are not allowed to use a free-d data zone. Doing this is undefined behavior, and anything could happen.

As to the question "why can you sometimes still visit an invalid address" (inside a free-d zone), the answer is implementation specific. In practice, on Linux, acquiring memory from the kernel is done thru the mmap(2) (or sometimes sbrk(2)) and releasing it back is done thru the munmap(2) syscalls, which are somehow expensive operations and deal with multiple of page length (often 4Kbytes). So the malloc implementation tries to avoid doing a lot of mmap and munmap syscalls, so usually manages the free-d memory zones differently, by organizing them so they could be reused by a further malloc without doing any mmap syscall. This explains that the memory zone still exist (even if it is inside malloc internal bookkeeping) and you can access it. But doing so will break the internal invariants of malloc and havoc will happen later.

BTW, an address is valid if it is inside the address space, and you can query the address space of process 1234 by reading (sequentially) the /proc/1234/maps file (a pseudo file with some specified textual content on Linux). From inside the process read /proc/self/maps. Try the command cat /proc/self/maps which shows the address space of the process running that cat command to understand more. See proc(5) man page.

Try to strace your simple program to understand what syscalls it is doing.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547