0

I have a pointer and by default it carries NULL then it waits for some event and gets a value if the event happens, later I am freeing the pointer somewhere else but even after freeing the pointer I am not making it NULL so it still keeps referencing the same memory location and I know the next malloc call might allocate that memory chunk to some other memory request!

pointer_type *p = NULL;
while (process_get_wakeup(//some logic//)) { 
        while ((qelem = (void*)process_dequeue(//some logic//)) != NULL) {
           p = (pointer_type *)qelem;
        }
        .
        .
        //goes into a loop of calls where free(p) is also done!
        .
        .
        //Printing value of p as %p gives this : 0xFF00000000

EDIT : I already know it not how we are supposed to do it, and I can't expect to retain the same value as that might be used for something else now, but what I want to know is why only a particular value of p is seen by me!

Does this value : 0xFF00000000 render any special meaning ?

Sumit Singh
  • 182
  • 3
  • 14
  • 1
    Possible duplicate of [Why is my pointer not null after free?](https://stackoverflow.com/questions/7608714/why-is-my-pointer-not-null-after-free) – Yunnosch Sep 11 '18 at 05:05
  • Don't make any assumptions about the pointer value returned by `malloc`. The only "special" pointer value that may be returned by `malloc` is `NULL`. – Jabberwocky Sep 11 '18 at 06:26
  • @Jabberwocky I really do acknowledge your point, but then what can be the purpose for this compiler for having this value "always" in the pointer which till now was accessing an out of context memory, since i didn't make it NULL explicitly ? – Sumit Singh Sep 11 '18 at 09:40
  • I think you should read the chapter dealing with dynamic memory allocation and pointers in your C text book. After `free(p)`, the _value_ of `p` is not changed, but `p` doesn't point anywhere, or in other words, it points to some memory that doesn't belong to you anymore and you cannot dereference `p` anymore. That's how the C language works. – Jabberwocky Sep 11 '18 at 10:02

2 Answers2

3

On the contrary - the pointer does not retain its value after free.

The C standard says that as soon as the object is freed or, more generally, its lifetime ends, the values of all pointers pointing to the object become indeterminate, and using such an indeterminate value can lead to undefined behaviour even if it was just printing the value. That it happens to look as if it retains its original value is in no way guaranteed.

This allows the C compiler to do optimizations within your function. For example if it used one CPU register to retain the value of p, after the free(p) call, the compiler knows that the register can be now used for something else, for example to store results of intermediate calculations of other operations, and its value does not need to be stored, until a new value is assigned to it.


As for the memory address of two distinct objects being the same - that is possible, if they are not alive at the same time. A single object will have a constant address for its entire lifetime. What happens after its lifetime is unspecified. malloc is often implemented as a list of free blocks, and the most-recently freed block is likely to be reused first.

  • p is not accessing the valid memory access as the memory is marked as free by the free call for it, but then are are you saying it is compiler optimisation to have the same value(0xFF00000000) for the dangling pointers when the memory which they r pointing is accessed by some valid pointer? – Sumit Singh Sep 11 '18 at 09:43
  • @SUMITKUMARSINGH ah no, I am saying that a "dangling pointer" need *not* retain its value if the compiler can prove so. – Antti Haapala -- Слава Україні Sep 11 '18 at 09:56
  • Correct!, my worry is why always the same value is seen as I was expecting random junk values. – Sumit Singh Sep 11 '18 at 10:06
  • 2
    @SUMITKUMARSINGH The pointer is indeterminate after you `free`, meaning you cannot expect it be anything--NULL, junk, or retain the same address--after you free. The second you call free you should stop caring what its pointing at. – Kcvin Sep 11 '18 at 14:36
  • @Kcvin: As a common extension, many implementations--especially those designed to be suitable for low-level programming or self-hosting--will allow some operations to be performed with pointers whose target has been released. Such implementations would also, typically e.g., allow an implementation to check whether `realloc` has moved a block, and assume that if the new and old pointers are identical, there would be no need to recompute pointers that identify locations within the block, which could save time if the realloc() shrinks a block and would thus be unlikely to move it. – supercat Oct 04 '18 at 19:21
  • @supercat that's nice, but it is not portable and does not follow C standard. – Kcvin Oct 10 '18 at 16:56
  • @Kcvin: Have you read the published Rationale for the C Standard? 'Although it strove to give programmers the opportunity to write truly portable programs, the C89 Committee did not want to force programmers into writing portably, to preclude the use of C as a “high-level assembler”: the ability to write machine specific code is one of the strengths of C.' Implementations that aren't going to be used for purposes requiring the semantic power of a 'high-level assembler' aren't required to support such semantics, but the authors of the Standard expressly acknowledged... – supercat Oct 10 '18 at 17:21
  • ...the existence and usefulness of implementations that do, and expressly did not intend to render the language unusable for purposes requiring such semantics. Bear in mind that while the Standard does not require that an implementation support all the semantics necessary to write functions like malloc() in C, many implementations use libraries which are, in fact, written in C; it would be pretty well impossible to implement a useful free() function if it couldn't do anything useful with the pointer (like make the space available for a future `malloc()` request. – supercat Oct 10 '18 at 17:27
  • @supercat Note that the standard specifically does mention both hosted and freestanding environments - in freestanding environment the names `malloc`, `realloc` and so would not be reserved. – Antti Haapala -- Слава Україні Oct 10 '18 at 18:27
  • @AnttiHaapala: Some compilers like gcc don't include library functions themselves but expect users to supply them, while still making assumptions about what they do (assuming, e.g. that `printf("Hello\n");` can be replaced with `puts("Hello");`, and many embedded compilers include many library functions but not enough to qualify as "hosted implementations". I think the intention of the Standard is that on implementations that don't define library functions, user code should be able to do so, but the Standard could really use some clarity here. For example... – supercat Oct 10 '18 at 18:33
  • ...it may be helpful to say that in such implementations, if code performs a `malloc` and later a `free`, and *a compiler can see that the pointer will never be dereferenced outside its range (nor exposed to code that might do so)*, it need not regard temporary acquisition via malloc/free as "observably" different from other forms of temporary acquisition such as stack allocation, even if the actual implementation of the library side-effects might have observable side-effects [e.g. producing a 'debug' log of allocation requests]. – supercat Oct 10 '18 at 18:40
  • @supercat `will allow some operations to be performed with pointers whose target has been released` ... Regardless of common extensions and what should be portable or not, wouldn't common sense say, don't use a pointer after its been freed? – Kcvin Oct 12 '18 at 15:44
  • @Kcvin: Printing the values of pointers that are freed can be useful if one is trying to debug the memory manager *itself*. Further, there are times where what a program would need for best efficiency would be a version of `realloc()` that will simply leave the old block as valid if it isn't necessary to move it. On some obscure platforms, it might be possible for a`realloc()` to return a pointer that is bit-for-bit identical to the old one, but nonetheless make other pointers to the block unusable. Consequently, the Standard treats `realloc()` as though it always frees the old block... – supercat Oct 12 '18 at 16:02
  • ...except in cases where it fails. If code performs a `malloc()` with an allocation that is expected to be larger than it will need, and then uses `realloc()` to shrink the allocation to the amount of space it actually used, however, then unless code needs to be compatible with obscure platforms, it should be possible to minimize redundant operations in the common case where the block stays put [IMHO, there should have been a `realloc`-like function that would when possible resize a block *without moving it*, and return the new size, but there isn't]. – supercat Oct 12 '18 at 16:08
  • You can always copy the pointer beforehand to an `uintptr_t` ;) – Antti Haapala -- Слава Україні Oct 12 '18 at 17:36
0

later I am freeing the pointer somewhere else ? Make sure you free p only when its gets assigned with dynamic memory address, otherwise it leads to undefined behavior.

p = NULL; /* now it's points to NULL */
p = malloc(SIZE); /* malloc() may give same previews memory location or may not */

From C standard, section 6.2.4

The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address, and retains its last-stored value throughout its lifetime. If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

And

I can't expect to retain the same value as that might be used for something else now?

you can't force malloc() to not to return the same old memory address after freed. Freed memory doesn't belong to your program anymore, next time when your process tries to allocate memory again, malloc() may return same address(not value) or may not.

Achal
  • 11,821
  • 2
  • 15
  • 37