-2

I have this code:

int * m = (int *)malloc(sizeof(int));
printf("%p %i\n", m, *m);
(*m) = 6;
printf("%p %i\n", m, *m);
free(m);
printf("%p %i\n", m, *m);

I run it on Linux. Why the value of the memory address is always 0?

Why if I run it on Windows this value changes?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 5
    After you call `free` you no longer own the memory pointed to by `m`. Dereferencing it will lead to *undefined behavior*. And if you have undefined behavior then your program is *ill-formed* and invalid. – Some programmer dude Jul 04 '17 at 10:51
  • 1
    Also, you need to cast `m` to `void *` to avoid undefined behavior. – ad absurdum Jul 04 '17 at 10:53
  • What do you mean "the value of the memory adress is always 0"? Nothing is 0 here – manatttta Jul 04 '17 at 10:53
  • You should not cast the return value of `malloc()` at all: https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc, note @DavidBowling and OP – Toby Jul 04 '17 at 10:54
  • 1
    @Toby , David is right, he is talking about the printf argument. – Sourav Ghosh Jul 04 '17 at 10:57
  • 1
    Short version - the state of the pointed to memory after using free is undefined. As such the implementation is free to do whatever it likes with that value. This means it can change with platform, compiler, compiler version, etc - thus a [programmer should not base code on expecting it to be a certain state nor even reason about it's state. – Toby Jul 04 '17 at 10:57
  • @SouravGhosh Ah, my bad! – Toby Jul 04 '17 at 10:57
  • 2
    Furthermore, the `malloc` function does not initialize the memory it allocates, its contents is *indeterminate*. Reading the contents of that memory (which you do with your very first dereference) *can* lead undefined behavior depending on the (seemingly random) contents. – Some programmer dude Jul 04 '17 at 10:58
  • 2
    C is a concise language for packing much undefined behavior into very few lines of code ;) – ad absurdum Jul 04 '17 at 11:02
  • I'm not sure what you mean by "the value of the memory address". If you mean, "Why is `*m` 0 after I call `free`?", the answer is, because malloc/free owns that memory, and when it's allocated to you you can do anything you want to with it and malloc/free won't touch it, but after you call free the memory belongs to malloc again, so malloc can do whatever it wants to with it. Perhaps it set it to 0 as part of its strategy for remembering that the memory was not in use, and was available for a future malloc call. (Footnote for nitpickers: yes, I know, it can't be that simple.) – Steve Summit Jul 04 '17 at 15:47

2 Answers2

8

Let us see the C11 standard, chapter §7.22.3.3.

The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. [....]

So, that means, the pointer which was passed to free() is no longer a "valid" pointer in your program context. Thereby, attempting to access the pointer, you're essentially accessing an invalid memory which causes undefined behavior.

Now, what actually happens to the memory location and to the content of the memory location, is depending on the memory manager or the OS. It could just be left as-is, unless it is required to be allocated again by some further calls, it could either be zeroed-out, anything...that is beyond the C standard specification.


Then, I'm not preaching for the coding style, but I personally find it handy to set any free-d pointer to NULL immediately after free(). "Most of the time", this will prevent any further use of the pointer (via a segfault), as NULL is definitely an invalid pointer in all context.


That said, some points regarding your code snippet,

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • But you can easily write to freed memory, can't you? – unalignedmemoryaccess Jul 04 '17 at 11:05
  • @tilz0R why? how? invalid is invalid, be it read or write.... – Sourav Ghosh Jul 04 '17 at 11:06
  • @tilz0R, what do you mean by "easily"? Yes, you can write code that attempts to write to freed memory, but what happens is Undefined. It might crash; it might appear to work; it might kill some unrelated program (ah, the fun of cooperative multitasking!). – Toby Speight Jul 04 '17 at 11:07
  • How? `*ptr = 5` for example. I do, of course, agree with you that it is undefined behaviour, but I'm trying to get a point what type of undefined behaviour is this. For example when doing `i = i++`, this is undefined behaviour because *compiler* does what it wants, but in case of free and malloc, this is not the same type of undefined behaviour. Pointer still points to RAM memory where you read or write, but now it will be undefined only because you can corrupt memory already allocated by another thread or process (whatever). – unalignedmemoryaccess Jul 04 '17 at 11:09
  • @TobySpeight Yes, that's what I'm trying to point for OP if it will read comments. – unalignedmemoryaccess Jul 04 '17 at 11:10
  • 1
    `free` function should be constructed as `free(void** p)` and then input pointer should be set to `NULL` automatically. – unalignedmemoryaccess Jul 04 '17 at 11:11
  • 2
    @tilz0R, are you trolling? There's only one valid declaration of `free`, and that's `free(void*)`. And there's only one kind of undefined behaviour, and that's Undefined. – Toby Speight Jul 04 '17 at 11:14
  • @TobySpeight Yes, only one is. That's why I used `should` infront. – unalignedmemoryaccess Jul 04 '17 at 11:14
1

After calling free(), the pointer itself contains the old address to memory which is now possibly invalid. The pointed-at value has an indeterminate value, which could be anything. Reading it can result in a crash, a random garbage value or some manner of seemingly deterministic value - what will happen is not well-defined.

You can't know what will happen and there are no guarantees. Therefore, pondering why you get a certain value when you do this is meaningless practice, even for learning purposes. You shouldn't access that memory, simple as that.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    The pointed-at memory may not even *exist* after `free()`: in a virtual-memory system, the containing page could be unmapped. The fact that the test program carries on running is a demonstration of how easy it is to have undiagnosed errors in a C program (and why tools such as Valgrind are so valuable). – Toby Speight Jul 04 '17 at 11:20