How to know the memory pointed by a ptr is freed?

R

ravi

I have a situation where i want to free the memory pointed by a
pointer, only if it is not freed already. Is there a way to know
whether the memory is freed or not?
 
J

Jens.Toerring

ravi said:
I have a situation where i want to free the memory pointed by a
pointer, only if it is not freed already. Is there a way to know
whether the memory is freed or not?

No. You got to store this bit of informatioon. The simplest method
is to set all pointers that pointed to memory you free()ed to NULL.
Than you have no chance to free() that memory region twice.

Regards, Jens
 
R

Ravi Uday

ravi said:
I have a situation where i want to free the memory pointed by a
pointer, only if it is not freed already. Is there a way to know
whether the memory is freed or not?

Its generally OS/system specific.
Generally there will be some 'poison pattern' written to the pointer if it
has been freed.
So the pattern might be of some clue.

Otherwise AFAIK there are no other ways of finding out whether a pointer is
freed apriorly..

- Ravi
 
K

Keith Thompson

Ravi Uday said:
Its generally OS/system specific.
Generally there will be some 'poison pattern' written to the pointer if it
has been freed.
So the pattern might be of some clue.

No, the pointer is typically left alone. The value becomes invalid,
but the bit pattern typically (arguably always) is left unchanged.

Given:

char *ptr = malloc(42);
...
free(ptr);

note that ptr is passed to the free() function by value. free() has
no access to the variable ptr, and can't modify it.

In fact, a subsequent call to malloc() is likely to reuse the same
address. If this happens, ptr will appear to be valid, and will
appear to point to the newly allocated memory -- but if you then call
free(ptr), you're going to clobber memory that was actually allocated
for something else.

The only way to know whether a pointer has been free()d is to keep
track of it yourself.
 
K

Kenny McCormack

No, the pointer is typically left alone. The value becomes invalid,
but the bit pattern typically (arguably always) is left unchanged.

Given:

char *ptr = malloc(42);
...
free(ptr);

note that ptr is passed to the free() function by value. free() has
no access to the variable ptr, and can't modify it.

The implication was that the memory area pointed to by "ptr" would be
scrambled in some implementation-defined way - not that ptr would itself be
modified. The point is that if this were done, then the programmer could,
in an implementation-specific way, tell if the memory was valid.
 
M

Malcolm

Kenny McCormack said:
The implication was that the memory area pointed to by "ptr" would be
scrambled in some implementation-defined way - not that ptr would itself be
modified. The point is that if this were done, then the programmer could,
in an implementation-specific way, tell if the memory was valid.
The implemetation is allowed to modify a pointer passed to free(). Generally
this isn't done because it is simpler to implement free() as a normal
function.
Some platforms do chew garbage, but usually not in performance-critical
mode. Anyway, this is a bad way to test a pointer. Firstly the garbage value
might be used for real data, and secondly and more importantly,
dereferencing a freed pointer causes undefined behaviour, so your program
would be incorrect (even if the technique happens to work on that platform)
..
 
K

Keith Thompson

The implication was that the memory area pointed to by "ptr" would be
scrambled in some implementation-defined way - not that ptr would itself be
modified. The point is that if this were done, then the programmer could,
in an implementation-specific way, tell if the memory was valid.

Hmm. I assumed that

Generally there will be some 'poison pattern' written to the
pointer if it has been freed.

referred to writing to the pointer itself, not writing through it.

But even if that's the case, you could still have the following:

char *ptr;
char *another_ptr;
ptr = malloc(42);
free(ptr); /* ptr is now invalid */
another_ptr = malloc(42); /* might re-use the same memory */

After the second malloc() call, it's likely (but by no means certain)
that ptr will still have the same value, and that it will point to the
chunk of memory allocated by the second call. In language terms, it's
invalid, but there's likely to be no way to detect that.

Bottom line: you just have to keep track of this stuff yourself.
 
K

Keith Thompson

Malcolm said:
The implemetation is allowed to modify a pointer passed to
free(). Generally this isn't done because it is simpler to implement
free() as a normal function.

This was discussed at length some time ago. I don't think there was
any consensus that an implementation is allowed to do this. It would
have to involve some kind of compiler "magic", since the argument to
free() can be any pointer expression, not necessarily a reference to a
pointer object.

Note that if an implementation does choose to modify a pointer passed
to free(), this could be visible to a strictly conforming program. It
could copy a pointer object's representation to an array of unsigned
char, call free(), copy the post-free() representation to another
array of unsigned char, and compare the arrays. If free() is required
to act like a function (in the sense that it can't modify its
argument), the arrays must appear equal.

In any case, this isn't particularly relevant for C programmers. Most
(all?) existing implementations leave the (now invalid) value in the
pointer object, and a program can't legitimately look at the pointer
value after the call to free() (other than by using the unsigned char
trick, but there's no good reason to do that).
 
D

Default User

Kenny said:
The implication was that the memory area pointed to by "ptr" would be
scrambled in some implementation-defined way - not that ptr would itself be
modified. The point is that if this were done, then the programmer could,
in an implementation-specific way, tell if the memory was valid.

It's still going to be Undefined Behavior to dereference that pointer.
Not to mention that memory that has been released with a call to free()
may well be reassigned via another call to *alloc(), so relying on some
pattern in the memory to tell whether is valid or not is a fool's
gambit.

If you really are incapable of keeping track, use a memory pool manager.




Brian Rodenborn
 
C

CBFalconer

Malcolm said:
[ freed pointers ]
The implication was that the memory area pointed to by "ptr"
would be scrambled in some implementation-defined way - not that
ptr would itself be modified. The point is that if this were
done, then the programmer could, in an implementation-specific
way, tell if the memory was valid.

The implemetation is allowed to modify a pointer passed to free().
Generally this isn't done because it is simpler to implement
free() as a normal function.

No it isn't. free receives a pointer by value, and has no idea
where the original value was stored.
 
R

RCollins

Malcolm said:
The implemetation is allowed to modify a pointer passed to free(). Generally
this isn't done because it is simpler to implement free() as a normal
function.

Actually, it's *required* to implement free() as a 'normal' function.
From the C89 standard:

<Q>
4.10.3.2 The free function


Synopsis

#include <stdlib.h>
void free(void *ptr);

Description

The free function causes the space pointed to by ptr to be
deallocated, that is, made available for further allocation. If ptr
is a null pointer, no action occurs. Otherwise, if the argument does
not match a pointer earlier returned by the calloc , malloc , or
realloc function, or if the space has been deallocated by a call to
free or realloc , the behavior is undefined.
</Q>

The definition alone specifies (void *ptr), which is a clue that
the value of "ptr" will not be changed.

OTOH (to play devil's advocate here), the same document says

<Q>
4.10.3 Memory management functions

The order and contiguity of storage allocated by successive calls
to the calloc , malloc , and realloc functions is unspecified. The
pointer returned if the allocation succeeds is suitably aligned so
that it may be assigned to a pointer to any type of object and then
used to access such an object in the space allocated (until the space
is explicitly freed or reallocated). Each such allocation shall yield
a pointer to an object disjoint from any other object. The pointer
returned points to the start (lowest byte address) of the allocated
space. If the space cannot be allocated, a null pointer is returned.
If the size of the space requested is zero, the behavior is
implementation-defined; the value returned shall be either a null
pointer or a unique pointer. The value of a pointer that refers to
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
freed space is indeterminate.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</Q>

Which would /imply/ that free() can change the value of "ptr".

Cheers,
Ron
 
E

E. Robert Tisdale

ravi said:
I have a situation where I want to free the memory
pointed [to] by a pointer, only if it is not freed already.
Is there a way to know whether the memory is freed or not?

#include <stdbool.h>
#include <stdlib.h>

typedef struct X {
int pattern;
} X;

inline static
X* X_new(void) {
X* p =(X*)malloc(sizeof(X));
p->pattern = 0X55555555;
return p;
}

inline static
bool X_valid(const X* p) {
return p->pattern == 0X55555555;
}

inline static
void X_delete(const X* p) {
if (NULL != p)
if (X_valid(p)) {
((X*)p)->pattern = 0XAAAAAAAA;
free((void*)p);
}
else {
// handle the error
}
}
 
K

kal

The implication was that the memory area pointed to by "ptr" would be
scrambled in some implementation-defined way - not that ptr would itself be
modified. The point is that if this were done, then the programmer could,
in an implementation-specific way, tell if the memory was valid.

Really? How amazing!

Could someone refer me to such an implementation.
A book/publication/webpage reference would do.
 
B

Ben Pfaff

The implication was that the memory area pointed to by "ptr" would be
scrambled in some implementation-defined way - not that ptr would itself be
modified. The point is that if this were done, then the programmer could,
in an implementation-specific way, tell if the memory was valid.

Hard to believe. With "normal" hardware, there's no bit pattern
that can be put into memory by free() that couldn't be put there
by the previous user of the memory. Thus, you could never be
sure that the memory was not valid for use.

(However, such a feature might be useful for debugging
nonetheless.)
 
K

Keith Thompson

RCollins said:
Malcolm wrote: [...]
The implemetation is allowed to modify a pointer passed to
free(). Generally this isn't done because it is simpler to
implement free() as a normal function.

Actually, it's *required* to implement free() as a 'normal' function.

That's the point that was debated here some time ago.
From the C89 standard: [...]
The definition alone specifies (void *ptr), which is a clue that
the value of "ptr" will not be changed.

Sure, it's a clue, but free could additionally be implemented as a
macro:

#define free(p) __builtin_free(p)

which can do whatever compile-time magic is necessary to figure out
whether the argument is an object.
OTOH (to play devil's advocate here), the same document says [...]
The value of a pointer that refers to
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
freed space is indeterminate.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</Q>

Which would /imply/ that free() can change the value of "ptr".

It's consistent with the assumption that free() cannot change the
value of ptr. For example:

char *p = malloc(sizeof *p);
/*
* Assume malloc succeeded, and the new value of p is represented
* as 0xDEADBEEF.
* 0xDEADBEEF is a valid address, pointing to the allocated memory.
*/
free(p);
/*
* Assuming no magic, free() receives a copy of the value of p, but
* has no way of knowing about the object p, and therefore no way
* of modifying it. The value of p is still represented as
* 0xDEADBEEF, but 0xDEADBEEF is now an indeterminate value.
* The value didn't change, but it became indeterminate.
*/

In my opinion, free(ptr) cannot legally change the value of ptr (other
than causing it to become indeterminate), but only because a strictly
conforming program can tell the difference if it does (by copying the
value of ptr to an array of unsigned bytes before and after the free()
and comparing the values). Note that directly examining the value of
ptr itself isn't allowed after the call to free().
 
G

Gordon Burditt

char *ptr = malloc(42);
The implication was that the memory area pointed to by "ptr" would be
scrambled in some implementation-defined way - not that ptr would itself be
modified. The point is that if this were done, then the programmer could,
in an implementation-specific way, tell if the memory was valid.

How portable is this, beyond the issue of the existence of SIGSEGV
in the first place? How likely is it the program will survive
testing an invalid or NULL pointer (that is, the program continues
with valid set to 0 or 1, as opposed to getting aborted with
or without core dump).

jmp_buf jmp;
int handler(int sig)
{
longjmp(jmp, 1);
}

int valid;
int *ptr;
... at this point ptr is set to some value that might be valid or
might not be ...
signal(SIGSEGV, handler);

if (setjmp(jmp) == 0) {
*ptr;
/* wild guess */
if (*ptr != 0xdeadbeef) {
valid = 1;
} else {
valid = 0;
}
} else {
/* here if smegfault dereferencing ptr */
valid = 0;
}
... continue here with valid set to guess about the pointer ...

Gordon L. Burditt
 
J

Jack Klein

Actually, it's *required* to implement free() as a 'normal' function.
From the C89 standard:

<Q>
4.10.3.2 The free function


Synopsis

#include <stdlib.h>
void free(void *ptr);

Description

The free function causes the space pointed to by ptr to be
deallocated, that is, made available for further allocation. If ptr
is a null pointer, no action occurs. Otherwise, if the argument does
not match a pointer earlier returned by the calloc , malloc , or
realloc function, or if the space has been deallocated by a call to
free or realloc , the behavior is undefined.
</Q>

The definition alone specifies (void *ptr), which is a clue that
the value of "ptr" will not be changed.

OTOH (to play devil's advocate here), the same document says

<Q>
4.10.3 Memory management functions

The order and contiguity of storage allocated by successive calls
to the calloc , malloc , and realloc functions is unspecified. The
pointer returned if the allocation succeeds is suitably aligned so
that it may be assigned to a pointer to any type of object and then
used to access such an object in the space allocated (until the space
is explicitly freed or reallocated). Each such allocation shall yield
a pointer to an object disjoint from any other object. The pointer
returned points to the start (lowest byte address) of the allocated
space. If the space cannot be allocated, a null pointer is returned.
If the size of the space requested is zero, the behavior is
implementation-defined; the value returned shall be either a null
pointer or a unique pointer. The value of a pointer that refers to
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
freed space is indeterminate.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</Q>

Which would /imply/ that free() can change the value of "ptr".

And what about the 37 copies made of that pointer after it was
returned from malloc() and passed to free()?

Or what about the suitably sized array of unsigned chars into which
the bit pattern of the pointer was copied by memcpy()?

The reason the term 'indeterminate' is used in this context is that
the standard makes any use of an 'indeterminate' value (other than
with an lvalue type other than unsigned char) undefined behavior.

Consider a platform like today's common desktop, with memory
management hardware. Freeing a pointer might cause the block of
virtual memory that mapped to it to be removed from the program's
address space. Attempting to dereference the pointer, or even compare
it with NULL, could trigger an exception when it is loaded into an
addressing register. That's a pretty good example of undefined
behavior.
 
J

Jack Klein

It's still going to be Undefined Behavior to dereference that pointer.
Not to mention that memory that has been released with a call to free()
may well be reassigned via another call to *alloc(), so relying on some
pattern in the memory to tell whether is valid or not is a fool's
gambit.

It's even undefined behavior to compare the pointer to NULL, although
I don't know of any hardware platform that would actually trap on it.
Doesn't mean there aren't any.
If you really are incapable of keeping track, use a memory pool manager.

....or explicitly set pointers to NULL immediately after freeing, but
that doesn't help if there might be copies around.
 
R

RCollins

Jack said:
On Tue, 17 Aug 2004 16:38:17 -0700, RCollins




And what about the 37 copies made of that pointer after it was
returned from malloc() and passed to free()?

Or what about the suitably sized array of unsigned chars into which
the bit pattern of the pointer was copied by memcpy()?

I don't know ... the standard doesn't mention them. All I know is that
the prototype for free() doesn't _appear_ to allow the value of "ptr"
to be changed. (Ignoring the possibility of behind-the-scenes
'compiler magic'). As for those 37 copies ... I'd say it was up to
the programmer to keep them straightened out properly.
The reason the term 'indeterminate' is used in this context is that
the standard makes any use of an 'indeterminate' value (other than
with an lvalue type other than unsigned char) undefined behavior.

While in a practical sense we all know what it means (or we should,
if we're going to make a living at this stuff), in another sense it
is somewhat ambiguous. After a call to free(), the value of "ptr"
is indeterminate. Does that mean that there is now a random bit
pattern stored in "ptr", or does it mean that we cannot under any
circumstances 'view' the bit pattern stored in "ptr"?

Of course, in the 'real world', it means neither. It simply means
that we gave that memory back to the system and any access to it
leads to undefined behavior.
Consider a platform like today's common desktop, with memory
management hardware. Freeing a pointer might cause the block of
virtual memory that mapped to it to be removed from the program's
address space. Attempting to dereference the pointer, or even compare
it with NULL, could trigger an exception when it is loaded into an
addressing register. That's a pretty good example of undefined
behavior.

Does this mean I can't copy out the bit pattern and view it?
(say, with a memcpy() into an array of unsigned chars). While
a bit pattern representing a trap may have been copied into "ptr",
I don't think free is _allowed_ to do that.

Here is the question it all boils down to:

Given that the standard specifies the prototype of free() to be
void free(void *ptr)

Is then free() *required* to behave that way? By the definition,
the bit pattern of "ptr" should not change; but is 'compiler magic'
allowed to happen here with a prototype that doesn't explicitly
*show* the value has changed?

Did I ask that clearly, or did I just muddle the waters?
 
R

RCollins

Keith said:
RCollins said:
Malcolm wrote:
[...]
The implemetation is allowed to modify a pointer passed to
free(). Generally this isn't done because it is simpler to
implement free() as a normal function.

Actually, it's *required* to implement free() as a 'normal' function.


That's the point that was debated here some time ago.

I missed that debate; I'll try to find it on Google and
catch up.
From the C89 standard:
[...]

The definition alone specifies (void *ptr), which is a clue that
the value of "ptr" will not be changed.


Sure, it's a clue, but free could additionally be implemented as a
macro:

#define free(p) __builtin_free(p)

which can do whatever compile-time magic is necessary to figure out
whether the argument is an object.

I dunno ... the standard shows the definition of free() as
void free(void *ptr)

If anybody looks at the standard to learn how to call free(),
they *should* be able to count on the value (i.e. the bit pattern)
of "ptr" not changing. (Why they would want to, I can't say).
OTOH (to play devil's advocate here), the same document says
[...]

The value of a pointer that refers to
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
freed space is indeterminate.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
</Q>

Which would /imply/ that free() can change the value of "ptr".


It's consistent with the assumption that free() cannot change the
value of ptr. For example:

char *p = malloc(sizeof *p);
/*
* Assume malloc succeeded, and the new value of p is represented
* as 0xDEADBEEF.
* 0xDEADBEEF is a valid address, pointing to the allocated memory.
*/
free(p);
/*
* Assuming no magic, free() receives a copy of the value of p, but
* has no way of knowing about the object p, and therefore no way
* of modifying it. The value of p is still represented as
* 0xDEADBEEF, but 0xDEADBEEF is now an indeterminate value.
* The value didn't change, but it became indeterminate.
*/

Ummm... what do you mean by "indeterminate"? I can do a memcpy()
of the bits in "p" to an array of unsigned char, and determine
*exactly* what the value is (or, simpler yet, since I know that
free() did not change "p", I can simply print it out before the
call to free() ... it will be the same after the call).

Or do we mean that I cannot 'see' the bits in "p" at all? That sounds
like a trap representation to me ... and traps are very deterministic
(there's only a limited number of them).

Or do we mean that I shouldn't be 'touching' the memory returned to
the system by free(), because we cannot determine the state of that
memory after the free() call?
In my opinion, free(ptr) cannot legally change the value of ptr (other
than causing it to become indeterminate), but only because a strictly
conforming program can tell the difference if it does (by copying the
value of ptr to an array of unsigned bytes before and after the free()
and comparing the values). Note that directly examining the value of
ptr itself isn't allowed after the call to free().

I agree; I think the whole issue boils down to a very convoluted and
complex warning about trying to access free()'d memory. (i.e., don't
do it!)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top