473,396 Members | 1,917 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

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

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?

Nov 14 '05 #1
72 3512
ravi <ec************@yahoo.com> wrote:
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
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #2

"ravi" <ec************@yahoo.com> wrote in message
news:cf********@odak26.prod.google.com...
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
Nov 14 '05 #3
"Ravi Uday" <ra******@gmail.com> writes:
"ravi" <ec************@yahoo.com> wrote in message
news:cf********@odak26.prod.google.com...
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.


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.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #4
In article <ln************@nuthaus.mib.org>,
Keith Thompson <ks***@mib.org> wrote:
"Ravi Uday" <ra******@gmail.com> writes:
"ravi" <ec************@yahoo.com> wrote in message
news:cf********@odak26.prod.google.com...
> 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.


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.

Nov 14 '05 #5

"Kenny McCormack" <ga*****@yin.interaccess.com> wrote
[ 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.
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)
..
Nov 14 '05 #6
ga*****@yin.interaccess.com (Kenny McCormack) writes:
In article <ln************@nuthaus.mib.org>,
Keith Thompson <ks***@mib.org> wrote:
"Ravi Uday" <ra******@gmail.com> writes:
"ravi" <ec************@yahoo.com> wrote in message
news:cf********@odak26.prod.google.com...
> 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.


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.


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.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #7
"Malcolm" <ma*****@55bank.freeserve.co.uk> writes:
[...]
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).

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #8
Kenny McCormack wrote:

In article <ln************@nuthaus.mib.org>,
Keith Thompson <ks***@mib.org> wrote:
"Ravi Uday" <ra******@gmail.com> writes:
Generally there will be some 'poison pattern' written to the pointer if it
has been freed.
So the pattern might be of some clue.
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.


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
Nov 14 '05 #9
Malcolm wrote:
"Kenny McCormack" <ga*****@yin.interaccess.com> wrote

[ 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.

--
"The most amazing achievement of the computer software industry
is its continuing cancellation of the steady and staggering
gains made by the computer hardware industry..." - Petroski
Nov 14 '05 #10


Malcolm wrote:
"Kenny McCormack" <ga*****@yin.interaccess.com> wrote
[ 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.


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

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)
.


--
Ron Collins
Air Defense/RTSC/BCS
"I have a plan so cunning, you could put a tail on it and call it a weasel"

Nov 14 '05 #11
kal
ga*****@yin.interaccess.com (Kenny McCormack) wrote in message news:<cf**********@yin.interaccess.com>...
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.
Nov 14 '05 #12
ga*****@yin.interaccess.com (Kenny McCormack) writes:
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.)
--
Ben Pfaff
email: bl*@cs.stanford.edu
web: http://benpfaff.org
Nov 14 '05 #13
ravi wrote:
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
}
}

Nov 14 '05 #14
RCollins <rc***@nospam.theriver.com> writes:
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().

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #15
>> 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.


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
Nov 14 '05 #16
On Tue, 17 Aug 2004 16:38:17 -0700, RCollins
<rc***@nospam.theriver.com> wrote in comp.lang.c:


Malcolm wrote:
"Kenny McCormack" <ga*****@yin.interaccess.com> wrote
[ 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.


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.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #17
On Tue, 17 Aug 2004 20:44:07 GMT, Default User
<fi********@boeing.com.invalid> wrote in comp.lang.c:
Kenny McCormack wrote:

In article <ln************@nuthaus.mib.org>,
Keith Thompson <ks***@mib.org> wrote:
"Ravi Uday" <ra******@gmail.com> writes: Generally there will be some 'poison pattern' written to the pointer if it
> has been freed.
> So the pattern might be of some clue.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.


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.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #18


Jack Klein wrote:
On Tue, 17 Aug 2004 16:38:17 -0700, RCollins
<rc***@nospam.theriver.com> wrote in comp.lang.c:

<snip>

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()?


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?
--
Ron Collins
Air Defense/RTSC/BCS
"I have a plan so cunning, you could put a tail on it and call it a weasel"

Nov 14 '05 #19


Keith Thompson wrote:
RCollins <rc***@nospam.theriver.com> writes:
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!)

--
Ron Collins
Air Defense/RTSC/BCS
"I have a plan so cunning, you could put a tail on it and call it a weasel"

Nov 14 '05 #20
>Keith Thompson wrote:
... 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.

True enough; but there must be a function version as well:

void (*fp)(void *);
...
fp = input_value == 42 ? free : zorg;
fp(ptr);

In the end, it is "too difficult" (and pointless, if you will pardon
the wording :-) ) for free() to change the bits stored in an object
passed to it.

In article <news:cf**********@pita.alt.net>
RCollins <rc***@nospam.theriver.com> wrote: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).


Here is the real problem -- the disconnect: the *bit pattern* and
the *value* are not the same thing!

Those who have written assembly code, or investigated thier C
implementations far enough, are already familiar with this with
respect to floating-point numbers. Typically "int" or "long"
is 4 or 8 bytes, and "float" or "double" is also 4 or 8 bytes
-- but a 4-byte "int" that represents (say) 12345 is *not*
also 12345.0f, not at all.

C99 makes it clear that there is a "representation" (as stored
in an object) for some particular value. The representation is
the bit-pattern in memory, and using "unsigned char *" pointers,
you can always inspect the representation of any addressable
object:

#include <stdio.h>

void show(const char *, void *, size_t);

int main(void) {
int i = 12345;
float f = 12345.0;

show("int i = 12345 ", &i, sizeof i);
show("float f = 12345.0", &f, sizeof f);
return 0;
}

void show(const char *prefix, void *mem, size_t len) {
size_t i;
unsigned char *cp = mem;

printf("%s:", prefix);
for (i = 0; i < len; i++)
printf(" %2.2x", (unsigned int)cp[i]);
printf("\n");
}

% cc -o t -O -ansi -pedantic -W -Wall t.c
% ./t
int i = 12345 : 39 30 00 00
float f = 12345.0: 00 e4 40 46
%

Now, the trick to free() is that, while it is virtually certain
not to change the bit pattern -- the *representation* of some value
-- what it *can* do is change the *meaning* of those bits. Just
as (in this case) the bits "39 30 00 00" "mean" 12345 when they
represent an int, we need a completely different set of bytes to
"mean" 12345.0 as a float. The free() function can, in effect,
change the way that a pointer is interpreted.

Imagine a system just like your typical 32-bit Intel, except that
pointers use *eight* bytes. Half the pointer is used as an index
into a table. When table[i] is set to 0, the pointer is considered
invalid, but when table[i] is set nonzero, the pointer is valid.
The free() function clears table[i] -- so now, even though the
"memory address" half of the pointer is still good, the pointer
itself is invalid.

The pointer is unchanged, but it has gone from "valid" to "invalid".
The *representation* is unchanged, but the *value* is different.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #21
RCollins <rc***@nospam.theriver.com> writes:
Keith Thompson wrote: [...] 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).
The object ptr can be viewed in more than one way. After a call to
free, attempting to view it as a pointer value invokes undefined
behavior -- but you can still legally view it (as you can view any
object) as an array of unsigned char.

[...] Ummm... what do you mean by "indeterminate"?
An indeterminate value is either an unspecified value or a trap
representation. You'd have to follow the maze of twisty definitions
in section 3 of the standard to understand precisely what unspecified
values and trap representations are, but basically it means that using
the value can invoke undefined behavior.

A "value" is the "precise meaning of the contents of an object when
interpreted as having a specific type". So the value of ptr when
viewed as a pointer is different from the value of ptr when viewed as
an array of unsigned char -- though both values have the same
representation. (Very roughly, value == representation + type.)
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).
memcpy() doesn't use the value of ptr *as a pointer*, so it doesn't
invoke undefined behavior.
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).
You can see the bits; you just can't see the pointer.

BTW, referring to a trap representation doesn't necessarily cause a
trap; undefined behavior can include behaving just as you'd expect it
to.
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?


It's also the case that you shouldn't touch the memory to which ptr
had pointed before the call to free() -- but the interesting thing is
that you shouldn't touch the value of ptr itself, even if you don't
dereference it.
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!)


Don't try to access free()'d memory *or* the value of the pointer that
pointed to it. The free()'d memory should be treated as if it no
longer exists; even an attempt to view it as an array of unsigned char
invokes undefined behavior. The pointer value is still there, sitting
in an object that you declared yourself, tempting you, begging you,
softly whispering "go ahead, access me, evaluate me, you know you're
curious, what could go wrong?", all the while getting the demons lined
up and ready to fly out your nose. (It's late; I *really* need to go
home.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #22

"Keith Thompson" <ks***@mib.org> wrote in message
news:ln************@nuthaus.mib.org...
RCollins <rc***@nospam.theriver.com> writes:
Keith Thompson wrote: [...]
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).


The object ptr can be viewed in more than one way. After a call to
free, attempting to view it as a pointer value invokes undefined
behavior -- but you can still legally view it (as you can view any
object) as an array of unsigned char.

[...]
Ummm... what do you mean by "indeterminate"?


An indeterminate value is either an unspecified value or a trap
representation. You'd have to follow the maze of twisty definitions
in section 3 of the standard to understand precisely what unspecified
values and trap representations are, but basically it means that using
the value can invoke undefined behavior.

A "value" is the "precise meaning of the contents of an object when
interpreted as having a specific type". So the value of ptr when
viewed as a pointer is different from the value of ptr when viewed as
an array of unsigned char -- though both values have the same
representation. (Very roughly, value == representation + type.)
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).


memcpy() doesn't use the value of ptr *as a pointer*, so it doesn't
invoke undefined behavior.
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).


You can see the bits; you just can't see the pointer.

Thats what the OP wanted, to know whether the pointer is valid.
I think the system/OS can fill the first word in the header of a freed
block with some
bit pattern (0xdeadbeef) before returning the call (free()) to the user
So seeing the memory dump of the pointer might be of clue.

Of-course you shouldnt de-reference the pointer once the free() returns !
BTW, referring to a trap representation doesn't necessarily cause a
trap; undefined behavior can include behaving just as you'd expect it
to.
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?
It's also the case that you shouldn't touch the memory to which ptr
had pointed before the call to free() -- but the interesting thing is
that you shouldn't touch the value of ptr itself, even if you don't
dereference it.
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!)


Don't try to access free()'d memory *or* the value of the pointer that
pointed to it. The free()'d memory should be treated as if it no
longer exists; even an attempt to view it as an array of unsigned char
invokes undefined behavior. The pointer value is still there, sitting
in an object that you declared yourself, tempting you, begging you,
softly whispering "go ahead, access me, evaluate me, you know you're
curious, what could go wrong?", all the while getting the demons lined
up and ready to fly out your nose. (It's late; I *really* need to go
home.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org

<http://www.ghoti.net/~kst> San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst> We must do something. This is something. Therefore, we must do this.

Nov 14 '05 #23
RCollins <rc***@nospam.theriver.com> wrote:

Jack Klein wrote:
On Tue, 17 Aug 2004 16:38:17 -0700, RCollins
<rc***@nospam.theriver.com> wrote in comp.lang.c:
<snip>

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()? 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?


I think it's not so much "compiler magic" but a question how the
underlying hardware works. Let's assume you have a machine that
has dedicated address registers (like e.g. the 68000 processors
had). Moreover, the OS is allowed to unmap the address from the
virual address space of a process once free() has called on a
pointer. If now the processor also tests if an address it loads
into an address register is mapped into the address space of the
process (with an exception for an address that represents the NULL
pointer) and e.g. segfaults when it isn't than you have a sitation
where none of the bits of the pointer ever changed but taking its
value (by loading it into an address register) isn't possible.

If memcpy()ing the content of that pointer somehwere else is
possible may depend on such a machine on what kind of machine
instructions are used in the process - if the value of the pointer
gets copied into an address register in the process it would
crash the program, if it's going in a data register (or no
register at all) it might work perfectly well.

While no machine is required to work that way it's possible to
write a conforming C compiler such a kind of machine. But
therefore you need some allowance in the standard that says
that "the result taking the value of a free()ed pointer is
indeterminate". Also a lot of other seemingly hard to explain
requirements (like, for example, why, when you have an array
a[10], calculating a+20 is undefined) suddenly make a lot of
sense on such a machine.
Regards, Jens
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #24


Je***********@physik.fu-berlin.de wrote:
RCollins <rc***@nospam.theriver.com> wrote:
Jack Klein wrote:
On Tue, 17 Aug 2004 16:38:17 -0700, RCollins
<rc***@nospam.theriver.com> wrote in comp.lang.c:

<snip>


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()?
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?

I think it's not so much "compiler magic" but a question how the
underlying hardware works. Let's assume you have a machine that
has dedicated address registers (like e.g. the 68000 processors
had). Moreover, the OS is allowed to unmap the address from the
virual address space of a process once free() has called on a
pointer. If now the processor also tests if an address it loads
into an address register is mapped into the address space of the
process (with an exception for an address that represents the NULL
pointer) and e.g. segfaults when it isn't than you have a sitation
where none of the bits of the pointer ever changed but taking its
value (by loading it into an address register) isn't possible.


No, this is too deep. Given the standard's definition of free(),
then I should be able to do this:

#include <stdio.h>

int mail(void) {
unsigned long before, after;
int *ptr;

ptr = malloc(100); /* ignore possible errors for now */
before = (unsigned long) ptr;
free(ptr);
after = (unsigned long) ptr;

if (before == after) printf("bits in ptr have not changed\n")
else printf("bits in ptr HAVE changed\n");

return 0;
}

And I should see that the bit representation in "ptr" have not
changed. Regardless of whether they point to a valid memory
location or not.


If memcpy()ing the content of that pointer somehwere else is
possible may depend on such a machine on what kind of machine
instructions are used in the process - if the value of the pointer
gets copied into an address register in the process it would
crash the program, if it's going in a data register (or no
register at all) it might work perfectly well.
Copying the (bits) contents of "ptr" to another location should
*always* be allowed; copying them back into "ptr" is another
question.

While no machine is required to work that way it's possible to
write a conforming C compiler such a kind of machine. But
therefore you need some allowance in the standard that says
that "the result taking the value of a free()ed pointer is
indeterminate". Also a lot of other seemingly hard to explain
requirements (like, for example, why, when you have an array
a[10], calculating a+20 is undefined) suddenly make a lot of
sense on such a machine.
Regards, Jens


Keep in mind the OP's original question: is there any way to know
if the bit representation in "ptr" is a valid memory location?

--
Ron Collins
Air Defense/RTSC/BCS
"I have a plan so cunning, you could put a tail on it and call it a weasel"

Nov 14 '05 #25
On Thu, 19 Aug 2004 08:19:51 -0700
RCollins <rc***@nospam.theriver.com> wrote:
Je***********@physik.fu-berlin.de wrote:
RCollins <rc***@nospam.theriver.com> wrote:
Jack Klein wrote:
On Tue, 17 Aug 2004 16:38:17 -0700, RCollins
<rc***@nospam.theriver.com> wrote in comp.lang.c:

<snip freed pointers>
No, this is too deep. Given the standard's definition of free(),
then I should be able to do this:

#include <stdio.h>

int mail(void) {
unsigned long before, after;
int *ptr;

ptr = malloc(100); /* ignore possible errors for now */
You failed to include stdlib.h which is required for malloc. Your
compiler was required to generate a diagnostic for this line if invoked
in ANSI/ISO mode.

On some REAL implementations thus would cause your program to fail.
before = (unsigned long) ptr;
Implementation defined behaviour. A pointer might require more bits than
a long.
free(ptr);
after = (unsigned long) ptr;
BANG. The pointer might be loaded in to an address register causing the
program to crash. The C standard does not allow you to read the value of
the pointer after you have freed it.
if (before == after) printf("bits in ptr have not changed\n")
else printf("bits in ptr HAVE changed\n");

return 0;
}

And I should see that the bit representation in "ptr" have not
changed. Regardless of whether they point to a valid memory
location or not.


The code you wanted was something like:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
int *ptr;
unsigned char before[sizeof ptr];

ptr = malloc(100); /* ignore possible errors for now */
memcpy( before, ptr, sizeof ptr );
free(ptr);

if (memcmp( before, ptr, sizeof ptr) == 0)
printf("bits in ptr have not changed\n")
else
printf("bits in ptr HAVE changed\n");
return 0;
}

If memcpy()ing the content of that pointer somehwere else is
possible may depend on such a machine on what kind of machine
instructions are used in the process - if the value of the pointer
gets copied into an address register in the process it would
crash the program, if it's going in a data register (or no
register at all) it might work perfectly well.


Copying the (bits) contents of "ptr" to another location should
*always* be allowed; copying them back into "ptr" is another
question.


Copying the bits is allowed, but casting a pointer to an unsigned long
does not copy the bits it takes the value and applies an implementation
defined translation. If you want to copy bits use memcpy as I did and
copy them in to a large enough array of unsigned char as unsigned char
is guaranteed by the standard to not have any trap values.
While no machine is required to work that way it's possible to
write a conforming C compiler such a kind of machine. But
therefore you need some allowance in the standard that says
that "the result taking the value of a free()ed pointer is
indeterminate". Also a lot of other seemingly hard to explain
requirements (like, for example, why, when you have an array
a[10], calculating a+20 is undefined) suddenly make a lot of
sense on such a machine.
Regards, Jens


Keep in mind the OP's original question: is there any way to know
if the bit representation in "ptr" is a valid memory location?


There is no standard way to find out. The only value that you cannot
dereference that you can portably detect is the null pointer.
--
Flash Gordon
Sometimes I think shooting would be far too good for some people.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #26
Flash Gordon wrote:

On Thu, 19 Aug 2004 08:19:51 -0700
RCollins <rc***@nospam.theriver.com> wrote:

ptr = malloc(100); /* ignore possible errors for now */


You failed to include stdlib.h which is required for malloc. Your
compiler was required to generate a diagnostic for this line if invoked
in ANSI/ISO mode.

Kind of depends on the compiler. C99 would require this, yes, but not
C89.

Brian Rodenborn
Nov 14 '05 #27
Je***********@physik.fu-berlin.de writes:
[snip]
I think it's not so much "compiler magic" but a question how the
underlying hardware works.

[snip]

After free(ptr), the value of ptr becomes indeterminate. That doesn't
require any "compiler magic", since it can become indeterminate
without any change in the bits.

A change in the bits that constitute the representatin of ptr would
require "compiler magic" (and would be of questionable legality).

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #28
On Thu, 19 Aug 2004 18:18:36 GMT
Default User <fi********@boeing.com.invalid> wrote:
Flash Gordon wrote:

On Thu, 19 Aug 2004 08:19:51 -0700
RCollins <rc***@nospam.theriver.com> wrote:

ptr = malloc(100); /* ignore possible errors for now */


You failed to include stdlib.h which is required for malloc. Your
compiler was required to generate a diagnostic for this line if
invoked in ANSI/ISO mode.


Kind of depends on the compiler. C99 would require this, yes, but not
C89.


No cast so as I understand it the compiler is required to raise a
diagnostic for assigning an integer (which it assumes malloc returns in
the absence of of a definition) to a pointer. One reason people around
here recommend against casting the return value of malloc :-)
--
Flash Gordon
Sometimes I think shooting would be far too good for some people.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #29
RCollins <rc***@nospam.theriver.com> writes:
[...]
No, this is too deep. Given the standard's definition of free(),
then I should be able to do this:

#include <stdio.h>

int mail(void) {
unsigned long before, after;
int *ptr;

ptr = malloc(100); /* ignore possible errors for now */
before = (unsigned long) ptr;
free(ptr);
after = (unsigned long) ptr;

if (before == after) printf("bits in ptr have not changed\n")
else printf("bits in ptr HAVE changed\n");

return 0;
}
ITYM "main", not "mail" (though of course a function called "mail" is
perfectly valid). And you're probably assuming that an int* will fit
into an unsigned long, which isn't guaranteed.

After the call to free(), the value if ptr is indeterminate. Any
reference to that value, even to convert it to unsigned long, causes
undefined behavior. On most or all real-world systems, the converson
just copies the bits, but it could, for example, load the pointer
value into an address register and trap if the pointer value is
invalid.

Here's my version of your program. Since refers to the representation
of ptr, not to its value as a pointer, it doesn't invoke undefined
behavior.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int *ptr;
unsigned char *before;
unsigned char *after;

/*
* We assume for now that all malloc() calls are successful.
*/
ptr = malloc(sizeof *ptr);
before = malloc(sizeof ptr);
memcpy(before, &ptr, sizeof ptr);
free(ptr);
after = malloc(sizeof ptr);
memcpy(after, &ptr, sizeof ptr);

if (memcmp(before, after, sizeof ptr) == 0) {
printf("bits in ptr have not changed\n");
}
else {
printf("bits in ptr have changed\n");
}
free(before);
free(after);

return 0;
}

This program (assuming all the malloc()s succeed) can print "bits in
ptr have changed" only if there's some compiler magic asociated with
the free() call that fiddles with ptr, even though the free() function
has no way within the language to know where ptr is, or even that the
argument was an object reference.

In my opinion, a conforming compiler cannot perform such magic. It's
not covered by the "as-if" rule because a program can detect it. A
*reasonable* program cannot detect it, and I wouldn't complain if the
standard were amended to allow this particular magic, but I don't
think that's going to happen.
Keep in mind the OP's original question: is there any way to know
if the bit representation in "ptr" is a valid memory location?


And the answer is: no, there's no portable way to do that. There may
be non-portable ways to do it, but only by depending on detailed
knowledge of the implementation (which could easily change with the
next release of the system).

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #30
Flash Gordon <sp**@flash-gordon.me.uk> writes:
[...]
The code you wanted was something like:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
int *ptr;
unsigned char before[sizeof ptr];

ptr = malloc(100); /* ignore possible errors for now */
memcpy( before, ptr, sizeof ptr );
free(ptr);

if (memcmp( before, ptr, sizeof ptr) == 0)
printf("bits in ptr have not changed\n")
else
printf("bits in ptr HAVE changed\n");
return 0;
}


Something like but not exactly like. You're missing a semicolon on
the first printf, and in the memcpy() and memcmp() calls you refer to
ptr where you should refer to &ptr. (As written, you're comparing the
first few bytes of the memory allocated by malloc(), not the bytes
making up the representation of ptr itself.)

Here's another version that fixes the bugs and is an improvement over
the version I posted a few minutes ago:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
int *ptr;
unsigned char before[sizeof ptr];

ptr = malloc(sizeof *ptr); /* assume malloc() succeeds */
memcpy( before, &ptr, sizeof ptr );
free(ptr);

if (memcmp( before, &ptr, sizeof ptr) == 0) {
printf("bits in ptr have not changed\n");
}
else {
printf("bits in ptr HAVE changed\n");
}
return 0;
}

(I had used malloc() to allocate the "before" and "after" arrays
because I forgot that sizeof ptr is a constant expression, a temporary
brain malfunction indirectly associated with the fact that you can't
use sizeof in a preprocessor expression.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #31


Flash Gordon wrote:
On Thu, 19 Aug 2004 08:19:51 -0700
RCollins <rc***@nospam.theriver.com> wrote:

Je***********@physik.fu-berlin.de wrote:
RCollins <rc***@nospam.theriver.com> wrote:


Jack Klein wrote:
>On Tue, 17 Aug 2004 16:38:17 -0700, RCollins
><rc***@nospam.theriver.com> wrote in comp.lang.c:

<snip freed pointers>
No, this is too deep. Given the standard's definition of free(),
then I should be able to do this:

#include <stdio.h>

int mail(void) {
unsigned long before, after;
int *ptr;

ptr = malloc(100); /* ignore possible errors for now */

You failed to include stdlib.h which is required for malloc. Your
compiler was required to generate a diagnostic for this line if invoked
in ANSI/ISO mode.


Let's not nit-pic the trivialities; this is example code, not
a lesson for a newbie.

On some REAL implementations thus would cause your program to fail.

before = (unsigned long) ptr;

Implementation defined behaviour. A pointer might require more bits than
a long.


Section 3.3.4 of the C89 standard expressly allows conversions between
pointers and integer types; it is up to the programmer to insure that
the integer type is wide enough to hold a pointer. Again, this is a
nit-pic; this is an example, not a lesson.

free(ptr);
after = (unsigned long) ptr;

BANG. The pointer might be loaded in to an address register causing the
program to crash. The C standard does not allow you to read the value of
the pointer after you have freed it.


Er ... no. Why would the contents of "ptr" be placed into an address
register? I would expect the address of "ptr" (i.e., &ptr) to be
loaded into an address register, and the contents of "ptr" to be
loaded into a data register.

Also, you can read the contents of "ptr" after a call to free(), but
you cannot read the contents of the memory *pointed to* by "ptr".

if (before == after) printf("bits in ptr have not changed\n")
else printf("bits in ptr HAVE changed\n");

return 0;
}

And I should see that the bit representation in "ptr" have not
changed. Regardless of whether they point to a valid memory
location or not.

The code you wanted was something like:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
int *ptr;
unsigned char before[sizeof ptr];

ptr = malloc(100); /* ignore possible errors for now */
memcpy( before, ptr, sizeof ptr );
free(ptr);

if (memcmp( before, ptr, sizeof ptr) == 0)
printf("bits in ptr have not changed\n")
else
printf("bits in ptr HAVE changed\n");
return 0;
}


I will concede the 'properness' of your code; let's just try
to focus on the question at hand.
If memcpy()ing the content of that pointer somehwere else is
possible may depend on such a machine on what kind of machine
instructions are used in the process - if the value of the pointer
gets copied into an address register in the process it would
crash the program, if it's going in a data register (or no
register at all) it might work perfectly well.
Copying the (bits) contents of "ptr" to another location should
*always* be allowed; copying them back into "ptr" is another
question.

Copying the bits is allowed, but casting a pointer to an unsigned long
does not copy the bits it takes the value and applies an implementation
defined translation. If you want to copy bits use memcpy as I did and
copy them in to a large enough array of unsigned char as unsigned char
is guaranteed by the standard to not have any trap values.


The bit about "implementation defined translation" is a good point,
and one well worth remembering. However, I can't think of any
modern common compiler that makes such a translation. (It doesn't
mean they don't exist, it just means I can't think of one).

While no machine is required to work that way it's possible to
write a conforming C compiler such a kind of machine. But
therefore you need some allowance in the standard that says
that "the result taking the value of a free()ed pointer is
indeterminate". Also a lot of other seemingly hard to explain
requirements (like, for example, why, when you have an array
a[10], calculating a+20 is undefined) suddenly make a lot of
sense on such a machine.
Regards, Jens


Keep in mind the OP's original question: is there any way to know
if the bit representation in "ptr" is a valid memory location?

There is no standard way to find out. The only value that you cannot
dereference that you can portably detect is the null pointer.


Agreed.

--
Ron Collins
Air Defense/RTSC/BCS
"I have a plan so cunning, you could put a tail on it and call it a weasel"

Nov 14 '05 #32


Keith Thompson wrote:
RCollins <rc***@nospam.theriver.com> writes:
[...]
No, this is too deep. Given the standard's definition of free(),
then I should be able to do this:

#include <stdio.h>

int mail(void) {
unsigned long before, after;
int *ptr;

ptr = malloc(100); /* ignore possible errors for now */
before = (unsigned long) ptr;
free(ptr);
after = (unsigned long) ptr;

if (before == after) printf("bits in ptr have not changed\n")
else printf("bits in ptr HAVE changed\n");

return 0;
}

ITYM "main", not "mail" (though of course a function called "mail" is
perfectly valid). And you're probably assuming that an int* will fit
into an unsigned long, which isn't guaranteed.

After the call to free(), the value if ptr is indeterminate. Any
reference to that value, even to convert it to unsigned long, causes
undefined behavior. On most or all real-world systems, the converson
just copies the bits, but it could, for example, load the pointer
value into an address register and trap if the pointer value is
invalid.

Here's my version of your program. Since refers to the representation
of ptr, not to its value as a pointer, it doesn't invoke undefined
behavior.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int *ptr;
unsigned char *before;
unsigned char *after;

/*
* We assume for now that all malloc() calls are successful.
*/
ptr = malloc(sizeof *ptr);
before = malloc(sizeof ptr);
memcpy(before, &ptr, sizeof ptr);
free(ptr);
after = malloc(sizeof ptr);
memcpy(after, &ptr, sizeof ptr);

if (memcmp(before, after, sizeof ptr) == 0) {
printf("bits in ptr have not changed\n");
}
else {
printf("bits in ptr have changed\n");
}
free(before);
free(after);

return 0;
}

This program (assuming all the malloc()s succeed) can print "bits in
ptr have changed" only if there's some compiler magic asociated with
the free() call that fiddles with ptr, even though the free() function
has no way within the language to know where ptr is, or even that the
argument was an object reference.

In my opinion, a conforming compiler cannot perform such magic. It's
not covered by the "as-if" rule because a program can detect it. A
*reasonable* program cannot detect it, and I wouldn't complain if the
standard were amended to allow this particular magic, but I don't
think that's going to happen.


Agreed ... this was the point of my (flawed) example.

Keep in mind the OP's original question: is there any way to know
if the bit representation in "ptr" is a valid memory location?

And the answer is: no, there's no portable way to do that. There may
be non-portable ways to do it, but only by depending on detailed
knowledge of the implementation (which could easily change with the
next release of the system).


Agreed here, also. I would tend to believe that the desire to
determine if a pointer is "valid" or not is a driving force behind
handle allocation in some OS's (i.e., doubly-indirect memory allocation,
similar to a "pointer to a pointer to an int").

--
Ron Collins
Air Defense/RTSC/BCS
"I have a plan so cunning, you could put a tail on it and call it a weasel"

Nov 14 '05 #33
Flash Gordon wrote:
No cast so as I understand it the compiler is required to raise a
diagnostic for assigning an integer (which it assumes malloc returns in
the absence of of a definition) to a pointer. One reason people around
here recommend against casting the return value of malloc :-)

Yes, of course. I thought you talking about diagnosing the missing
include. The assignment without cast should generate a diagnostic.


Brian Rodenborn
Nov 14 '05 #34
RCollins <rc***@nospam.theriver.com> writes:
Flash Gordon wrote: [...]
You failed to include stdlib.h which is required for malloc. Your
compiler was required to generate a diagnostic for this line if invoked
in ANSI/ISO mode.


Let's not nit-pic the trivialities; this is example code, not
a lesson for a newbie.


If you don't want trivialities nit-picked, I humbly submit that you've
come to the wrong newsgroup. 8-)}

[...]
BANG. The pointer might be loaded in to an address register causing
the
program to crash. The C standard does not allow you to read the value of
the pointer after you have freed it.


Er ... no. Why would the contents of "ptr" be placed into an address
register? I would expect the address of "ptr" (i.e., &ptr) to be
loaded into an address register, and the contents of "ptr" to be
loaded into a data register.


Why *wouldn't* the contents of "ptr" be placed into an address
register?

If you're going to assume characteristics that are common to most
real-world implementations but aren't guaranteed by the standard, you
might as well just save the value as a pointer:

int *ptr = malloc(whatever);
int *before = ptr;
free(ptr);
if (ptr == before) { /* warning: undefined behavior */
printf("bits didn't change\n");
}
else {
printf("bits changed\n");
}

Or, for that matter:

printf("bits didn't change\n"); /* 8-)} */

If you're going to avoid undefined behavior, there's not much point in
going halfway. memcpy()ing the value to an array of unsigned char
avoids UB; casting to unsigned long doesn't.
Also, you can read the contents of "ptr" after a call to free(), but
you cannot read the contents of the memory *pointed to* by "ptr".


That's incorrect.

In most real-world implementations, you can successfully read both the
contents of ptr and the memory pointed to by ptr after a call to
free(). It's undefined behavior, but most implementations don't do
anything to make it fail. An address is an address, memory is memory,
and you can still read it even if you no longer "own" it. (In some
cases, if the memory is actually returned to the OS and removed from
the program's visible memory space, a reference to the deallocated
memory might actually trap; a reference to just the pointer value is
less likely to do so.)

But as far as the standard is concerned, attempting to refer to the
allocated memory after the call to free() invokes undefined behavior
(as you know) *and* the pointer value itself becomes indeterminate
(even if the bits don't change), so any attempt to refer to that value
will also invoke undefined behavior. Even this:

free(ptr);
if (ptr == NULL) { ... }

or this:

free(ptr);
unsigned long foo = (unsigned long)ptr;

invokes undefined behavior. It happens that the typical result of
this undefined behavior is to read the value of ptr, but the standard
allows nasal daemons.

Why is it defined this way? Because, for example, a conforming
implementation might implement any reference to a pointer value
(including a comparison to NULL or a conversion to unsigned long) by
loading the pointer value into an address register, and the act of
loading the value might do a validity check, and trap if it's invalid.
Such a trap is not required, of course, but the point is that the
standard doesn't render such an implementation non-conforming.

There could be other reasons why referring to the value of ptr might
cause problems; the address register thing is just one possible
example.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #35
On Thu, 19 Aug 2004 20:19:29 GMT
Keith Thompson <ks***@mib.org> wrote:
Flash Gordon <sp**@flash-gordon.me.uk> writes:
[...]
The code you wanted was something like:

<snip faulty code>
Something like but not exactly like. You're missing a semicolon on
the first printf, and in the memcpy() and memcmp() calls you refer to
ptr where you should refer to &ptr. (As written, you're comparing the
first few bytes of the memory allocated by malloc(), not the bytes
making up the representation of ptr itself.)


Oops. That'll teach me to not take a 5 minute break from work to read
and post here. :-/
--
Flash Gordon
Sometimes I think shooting would be far too good for some people.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #36
On Thu, 19 Aug 2004 14:02:44 -0700
RCollins <rc***@nospam.theriver.com> wrote:
Flash Gordon wrote:
On Thu, 19 Aug 2004 08:19:51 -0700
RCollins <rc***@nospam.theriver.com> wrote:
Je***********@physik.fu-berlin.de wrote:

RCollins <rc***@nospam.theriver.com> wrote:


>Jack Klein wrote:
>>On Tue, 17 Aug 2004 16:38:17 -0700, RCollins
>><rc***@nospam.theriver.com> wrote in comp.lang.c:

<snip freed pointers>
No, this is too deep. Given the standard's definition of free(),
then I should be able to do this:

#include <stdio.h>

int mail(void) {
unsigned long before, after;
int *ptr;

ptr = malloc(100); /* ignore possible errors for now */


You failed to include stdlib.h which is required for malloc. Your
compiler was required to generate a diagnostic for this line if
invoked in ANSI/ISO mode.


Let's not nit-pic the trivialities; this is example code, not
a lesson for a newbie.


It is a serious flaw (not that I always post correct code) which will
cause it to fail on some implementations.
On some REAL implementations thus would cause your program to fail.

before = (unsigned long) ptr;

Implementation defined behaviour. A pointer might require more bits
than a long.


Section 3.3.4 of the C89 standard expressly allows conversions between
pointers and integer types; it is up to the programmer to insure that
the integer type is wide enough to hold a pointer. Again, this is a
nit-pic; this is an example, not a lesson.


You've not quoted the exact wording and I don't have the C89 standard.
However, I do not believe (based on posts of long time members of this
group) that it required that there is ANY integer type large enough.
Also, I have seen mention here of implementations where pointers are
definitely larger than the largest integer type.
free(ptr);
after = (unsigned long) ptr;

BANG. The pointer might be loaded in to an address register causing
the program to crash. The C standard does not allow you to read the
value of the pointer after you have freed it.


Er ... no. Why would the contents of "ptr" be placed into an address
register?


Because it is a pointer?
I would expect the address of "ptr" (i.e., &ptr) to be
loaded into an address register, and the contents of "ptr" to be
loaded into a data register.

Also, you can read the contents of "ptr" after a call to free(), but
you cannot read the contents of the memory *pointed to* by "ptr".


No, the value is indeterminate and hence reading it invokes undefined
behaviour. You can still read the representation using a pointer to
unsigned char or by using memcpy etc.
if (before == after) printf("bits in ptr have not changed\n")
else printf("bits in ptr HAVE changed\n");

return 0;
}

And I should see that the bit representation in "ptr" have not
changed. Regardless of whether they point to a valid memory
location or not.

The code you wanted was something like:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
int *ptr;
unsigned char before[sizeof ptr];

ptr = malloc(100); /* ignore possible errors for now */
memcpy( before, ptr, sizeof ptr );
free(ptr);

if (memcmp( before, ptr, sizeof ptr) == 0)
printf("bits in ptr have not changed\n")
else
printf("bits in ptr HAVE changed\n");
return 0;
}


I will concede the 'properness' of your code; let's just try
to focus on the question at hand.


Someone else pointed out that my code had flaws as well. :-/
If memcpy()ing the content of that pointer somehwere else is
possible may depend on such a machine on what kind of machine
instructions are used in the process - if the value of the pointer
gets copied into an address register in the process it would
crash the program, if it's going in a data register (or no
register at all) it might work perfectly well.

Copying the (bits) contents of "ptr" to another location should
*always* be allowed; copying them back into "ptr" is another
question.


Copying the bits is allowed, but casting a pointer to an unsigned
long does not copy the bits it takes the value and applies an
implementation defined translation. If you want to copy bits use
memcpy as I did and copy them in to a large enough array of unsigned
char as unsigned char is guaranteed by the standard to not have any
trap values.


The bit about "implementation defined translation" is a good point,
and one well worth remembering. However, I can't think of any
modern common compiler that makes such a translation. (It doesn't
mean they don't exist, it just means I can't think of one).


I'm sure someone here can point out an implementation with pointers
larger than the largest integer, whether it is modern is another
question.

<snip>
Keep in mind the OP's original question: is there any way to know
if the bit representation in "ptr" is a valid memory location?

There is no standard way to find out. The only value that you cannot
dereference that you can portably detect is the null pointer.


Agreed.


At least we agree on some things. :-)
--
Flash Gordon
Sometimes I think shooting would be far too good for some people.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #37


Keith Thompson wrote:
RCollins <rc***@nospam.theriver.com> writes:
Flash Gordon wrote:
[...]
You failed to include stdlib.h which is required for malloc. Your
compiler was required to generate a diagnostic for this line if invoked
in ANSI/ISO mode.


Let's not nit-pic the trivialities; this is example code, not
a lesson for a newbie.

If you don't want trivialities nit-picked, I humbly submit that you've
come to the wrong newsgroup. 8-)}


I think you are right ...

[...]
BANG. The pointer might be loaded in to an address register causing
the
program to crash. The C standard does not allow you to read the value of
the pointer after you have freed it.


Er ... no. Why would the contents of "ptr" be placed into an address
register? I would expect the address of "ptr" (i.e., &ptr) to be
loaded into an address register, and the contents of "ptr" to be
loaded into a data register.

Why *wouldn't* the contents of "ptr" be placed into an address
register?

If you're going to assume characteristics that are common to most
real-world implementations but aren't guaranteed by the standard, you
might as well just save the value as a pointer:

int *ptr = malloc(whatever);
int *before = ptr;
free(ptr);
if (ptr == before) { /* warning: undefined behavior */
printf("bits didn't change\n");
}
else {
printf("bits changed\n");
}

Or, for that matter:

printf("bits didn't change\n"); /* 8-)} */

If you're going to avoid undefined behavior, there's not much point in
going halfway. memcpy()ing the value to an array of unsigned char
avoids UB; casting to unsigned long doesn't.

Also, you can read the contents of "ptr" after a call to free(), but
you cannot read the contents of the memory *pointed to* by "ptr".

That's incorrect.

In most real-world implementations, you can successfully read both the
contents of ptr and the memory pointed to by ptr after a call to
free(). It's undefined behavior, but most implementations don't do
anything to make it fail. An address is an address, memory is memory,
and you can still read it even if you no longer "own" it. (In some
cases, if the memory is actually returned to the OS and removed from
the program's visible memory space, a reference to the deallocated
memory might actually trap; a reference to just the pointer value is
less likely to do so.)

But as far as the standard is concerned, attempting to refer to the
allocated memory after the call to free() invokes undefined behavior
(as you know) *and* the pointer value itself becomes indeterminate
(even if the bits don't change), so any attempt to refer to that value
will also invoke undefined behavior. Even this:

free(ptr);
if (ptr == NULL) { ... }

or this:

free(ptr);
unsigned long foo = (unsigned long)ptr;

invokes undefined behavior. It happens that the typical result of
this undefined behavior is to read the value of ptr, but the standard
allows nasal daemons.

Why is it defined this way? Because, for example, a conforming
implementation might implement any reference to a pointer value
(including a comparison to NULL or a conversion to unsigned long) by
loading the pointer value into an address register, and the act of
loading the value might do a validity check, and trap if it's invalid.
Such a trap is not required, of course, but the point is that the
standard doesn't render such an implementation non-conforming.

There could be other reasons why referring to the value of ptr might
cause problems; the address register thing is just one possible
example.


Thanks for the explanation; that was very clear and well presented.
And yet a nagging question keeps going around in my mind ... you
say that a construct of the form

unsigned long foo = (unsigned long)ptr;

can lead to UB (since the compiler may perform some interpretation
of ptr), and yet

unsigned char foo[4]; /* just making an assumption for this example */
memcpy(foo, &ptr, sizeof(ptr));

does _not_ invoke UB. Why not? Isn't the compiler here able
to perform the same interpretation of "ptr" as it did on the
cast to an unsigned long?

--
Ron Collins
Air Defense/RTSC/BCS
"I have a plan so cunning, you could put a tail on it and call it a weasel"

Nov 14 '05 #38


Flash Gordon wrote:
On Thu, 19 Aug 2004 14:02:44 -0700
RCollins <rc***@nospam.theriver.com> wrote:
<snip>

Section 3.3.4 of the C89 standard expressly allows conversions between
pointers and integer types; it is up to the programmer to insure that
the integer type is wide enough to hold a pointer. Again, this is a
nit-pic; this is an example, not a lesson.

You've not quoted the exact wording and I don't have the C89 standard.
However, I do not believe (based on posts of long time members of this
group) that it required that there is ANY integer type large enough.
Also, I have seen mention here of implementations where pointers are
definitely larger than the largest integer type.


The text is (from C89):
....
Conversions that involve pointers (other than as permitted by the
constraints of $3.3.16.1) shall be specified by means of an explicit
cast; they have implementation-defined aspects: A pointer may be
converted to an integral type. The size of integer required and the
result are implementation-defined. If the space provided is not long
enough, the behavior is undefined.
....

As I noted, it is up to the programmer to make sure the integer type
is wide enough to contain a pointer (and vice versa). And you are
correct, it DOES NOT guarantee that any integer type is wide enough
for the conversion.
free(ptr);
after = (unsigned long) ptr;
BANG. The pointer might be loaded in to an address register causing
the program to crash. The C standard does not allow you to read the
value of the pointer after you have freed it.
Er ... no. Why would the contents of "ptr" be placed into an address
register?

Because it is a pointer?


That didn't make sense to me until Keith made his post ... as I
understand it now, an implementation *might* *always* load pointer
values into an address register (or an equivalent construct), and
test for validity.

I would expect the address of "ptr" (i.e., &ptr) to be
loaded into an address register, and the contents of "ptr" to be
loaded into a data register.

Also, you can read the contents of "ptr" after a call to free(), but
you cannot read the contents of the memory *pointed to* by "ptr".

No, the value is indeterminate and hence reading it invokes undefined
behaviour. You can still read the representation using a pointer to
unsigned char or by using memcpy etc.


See my response to Keith, where I ask "what is the difference between
a cast from ptr vs. a memcpy() from ptr". It seems to me that if
an implementation is *always* going to check the validity of a pointer,
then it would catch it (invalid pointer) regardless of the method used.

Keep in mind the OP's original question: is there any way to know
if the bit representation in "ptr" is a valid memory location?
There is no standard way to find out. The only value that you cannot
dereference that you can portably detect is the null pointer.


Agreed.

At least we agree on some things. :-)


We'll agree on more as I learn more.

--
Ron Collins
Air Defense/RTSC/BCS
"I have a plan so cunning, you could put a tail on it and call it a weasel"

Nov 14 '05 #39
RCollins <rc***@nospam.theriver.com> writes:
[snip]
Thanks for the explanation; that was very clear and well presented.
Thanks.
And yet a nagging question keeps going around in my mind ... you
say that a construct of the form

unsigned long foo = (unsigned long)ptr;

can lead to UB (since the compiler may perform some interpretation
of ptr), and yet

unsigned char foo[4]; /* just making an assumption for this example */
or unsigned char foo[sizeof ptr]; /* no assumption necessary */
memcpy(foo, &ptr, sizeof(ptr));

does _not_ invoke UB. Why not? Isn't the compiler here able
to perform the same interpretation of "ptr" as it did on the
cast to an unsigned long?


The UB happens when the value of ptr is evaluated *as a pointer*.
Taking its address with "&ptr" is ok because it just gives you the
address of an object you own, without reference to its value.
Computing its size with "sizeof ptr" doesn't evaluate anything; it
just tells you how big the object is (something that can be done at
compilation time). This information is passed to memcpy(), which just
deals with bytes, not with pointers.

And now for something completely different: a Monty Python explanation
of invalid pointers.

The infamous Killer Joke was a joke so funny that anyone hearing it
would immediately die of laughter. The Allies worked to translate it
into German so they could use it as a weapon. Each translator worked
on only one word of the joke (one translator who accidentally saw two
consecutive words spent several weeks in hospital). Each individual
word of the Killer Joke is harmless. Only the entire joke is deadly.

An invalid pointer is the Killer Joke, deadly to anyone who reads it.
The individual bytes composing the pointer are the words of the joke,
harmless in themselves.

The gentlemen of Monty Python are, of course, masters of Undefined
Behavior.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #40
RCollins wrote:
Keith Thompson wrote: [...]
If you don't want trivialities nit-picked, I humbly submit that you've
come to the wrong newsgroup. 8-)}

I think you are right ...


More to the point, programming is about nit-picking. If just anyone
could tell the computer, "Hey, solve this problem," programming would
pay less than minimum wage and be done by teenagers under the Republican
"Hire teenagers at below minimum wage to replace adults" job program.
Nov 14 '05 #41
On Thu, 19 Aug 2004 17:51:12 -0700
RCollins <rc***@nospam.theriver.com> wrote:
Flash Gordon wrote:
On Thu, 19 Aug 2004 14:02:44 -0700
RCollins <rc***@nospam.theriver.com> wrote:
<snip>

Section 3.3.4 of the C89 standard expressly allows conversions

between>pointers and integer types; it is up to the programmer to
insure that>the integer type is wide enough to hold a pointer.
Again, this is a>nit-pic; this is an example, not a lesson.
You've not quoted the exact wording and I don't have the C89
standard. However, I do not believe (based on posts of long time
members of this group) that it required that there is ANY integer
type large enough. Also, I have seen mention here of implementations
where pointers are definitely larger than the largest integer type.


The text is (from C89):
...
Conversions that involve pointers (other than as permitted by the
constraints of $3.3.16.1) shall be specified by means of an explicit
cast; they have implementation-defined aspects: A pointer may be
converted to an integral type. The size of integer required and the
result are implementation-defined. If the space provided is not long
enough, the behavior is undefined.
...


Thank you.
As I noted, it is up to the programmer to make sure the integer type
is wide enough to contain a pointer (and vice versa). And you are
correct, it DOES NOT guarantee that any integer type is wide enough
for the conversion.


So it's worse than I thought in the worst case. You get Undefined
behaviour. :-/

<snip>
I would expect the address of "ptr" (i.e., &ptr) to be
loaded into an address register, and the contents of "ptr" to be
loaded into a data register.

Also, you can read the contents of "ptr" after a call to free(), but
you cannot read the contents of the memory *pointed to* by "ptr".

No, the value is indeterminate and hence reading it invokes
undefined behaviour. You can still read the representation using a
pointer to unsigned char or by using memcpy etc.


See my response to Keith, where I ask "what is the difference between
a cast from ptr vs. a memcpy() from ptr". It seems to me that if
an implementation is *always* going to check the validity of a
pointer, then it would catch it (invalid pointer) regardless of the
method used.


Kieth has again provided a good explanation. memcpy does not treat ptr
as a pointer, it treats it as an array of unsigned char. Or in other
words, the standard allows you to do it so the implementation has to
allow you to do it. :-)

<snip>
At least we agree on some things. :-)


We'll agree on more as I learn more.


Those willing to learn from the answers are worth answering. :-)

I've learnt a number of useful things here.
--
Flash Gordon
Sometimes I think shooting would be far too good for some people.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #42
In article <news:pd************@brenda.flash-gordon.me.uk>
Flash Gordon <sp**@flash-gordon.me.uk> wrote (in part):
I'm sure someone here can point out an implementation with pointers
larger than the largest integer, whether it is modern is another
question.


IBM AS/400, at least for "pointer to function". (Probably also for
"pointer to data" too, but I do not have an AS/400 implementation
handy to check; mainly I remember that function pointers were about
a million times bigger than data pointers. :-) OK, maybe 4 or 8
times bigger -- lots more bytes, anyway.)

AS/400s are being sold today, and as far as I know, have at least
C89-conforming compilers. (Remember that the AS/400 is sort of a
"virtual architecture", in the same way the S/370 architecture
was implemented in lots of different kinds of hardware, including
re-microcoded 68000 CPUs.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #43
Flash Gordon wrote:

[ snip ]

I never know where (or whether) to enter these incredible threads
but I do have something to share on the Subject.

Some time ago I determined to add 'size_t size(void *);' to my
otherwise meager bag of tricks.

In the simplist case, a call to malloc() is directed to a wrapper
that actually calls malloc but 'remembers' the size_t argument as
well as the void* return and saves them in a simple linked list.

A call to size(void *p) trips through the linked list looking for
the vallue of p and returns the size of the allocation if found,
else 0. Perfect.

Of course, I wrap free(void *p) as well. We trip through the list
looking for p and freeing it if we find it and removing p's node
from the list. Of course, if we don't find p in the list, we do nothing.

That's when it struck me, I can pass anything to free() and if it's
not found in the list, nothing happens. No danger.

I added another function, 'void freeall(void);' to trip through the
list, freeing the allocations and the list nodes themselves, maybe
just before exiting your program.

--
Joe Wright mailto:jo********@comcast.net
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 14 '05 #44
Joe Wright wrote:

I never know where (or whether) to enter these incredible threads
but I do have something to share on the Subject.

Some time ago I determined to add 'size_t size(void *);' to my
otherwise meager bag of tricks.

In the simplist case, a call to malloc() is directed to a wrapper
that actually calls malloc but 'remembers' the size_t argument as
well as the void* return and saves them in a simple linked list.

A call to size(void *p) trips through the linked list looking for
the vallue of p and returns the size of the allocation if found,
else 0. Perfect.

Of course, I wrap free(void *p) as well. We trip through the list
looking for p and freeing it if we find it and removing p's node
from the list. Of course, if we don't find p in the list, we do nothing.

That's when it struck me, I can pass anything to free() and if it's
not found in the list, nothing happens. No danger.

I added another function, 'void freeall(void);' to trip through the
list, freeing the allocations and the list nodes themselves, maybe
just before exiting your program.


Er - what about realloc?

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #45
CBFalconer wrote:
Joe Wright wrote:
I never know where (or whether) to enter these incredible threads
but I do have something to share on the Subject.

Some time ago I determined to add 'size_t size(void *);' to my
otherwise meager bag of tricks.

In the simplist case, a call to malloc() is directed to a wrapper
that actually calls malloc but 'remembers' the size_t argument as
well as the void* return and saves them in a simple linked list.

A call to size(void *p) trips through the linked list looking for
the vallue of p and returns the size of the allocation if found,
else 0. Perfect.

Of course, I wrap free(void *p) as well. We trip through the list
looking for p and freeing it if we find it and removing p's node
from the list. Of course, if we don't find p in the list, we do nothing.

That's when it struck me, I can pass anything to free() and if it's
not found in the list, nothing happens. No danger.

I added another function, 'void freeall(void);' to trip through the
list, freeing the allocations and the list nodes themselves, maybe
just before exiting your program.

Er - what about realloc?


Of course, realloc and calloc are included.

--
Joe Wright mailto:jo********@comcast.net
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 14 '05 #46
Joe Wright <jo********@comcast.net> writes:
I never know where (or whether) to enter these incredible threads
but I do have something to share on the Subject.

Some time ago I determined to add 'size_t size(void *);' to my
otherwise meager bag of tricks.

In the simplist case, a call to malloc() is directed to a wrapper
that actually calls malloc but 'remembers' the size_t argument as
well as the void* return and saves them in a simple linked list.

A call to size(void *p) trips through the linked list looking for
the vallue of p and returns the size of the allocation if found,
else 0. Perfect.

Of course, I wrap free(void *p) as well. We trip through the list
looking for p and freeing it if we find it and removing p's node
from the list. Of course, if we don't find p in the list, we do nothing.

That's when it struck me, I can pass anything to free() and if it's
not found in the list, nothing happens. No danger.

I added another function, 'void freeall(void);' to trip through the
list, freeing the allocations and the list nodes themselves, maybe
just before exiting your program.


A nice technique. Thank you for sharing it.

By the way, if a hash table were used rather than a linked list, that
might add a little bit of memory usage, but would greatly speed up
both 'size()' and the 'free()' wrapper.

A binary tree would be another possibility; if this were done the
tree would likely need automatic rebalancing of some kind.
Nov 14 '05 #47

"Joe Wright" <jo********@comcast.net> wrote in message
news:ut********************@comcast.com...
Flash Gordon wrote:

[ snip ]

I never know where (or whether) to enter these incredible threads
but I do have something to share on the Subject.

Some time ago I determined to add 'size_t size(void *);' to my
otherwise meager bag of tricks.

In the simplist case, a call to malloc() is directed to a wrapper
that actually calls malloc but 'remembers' the size_t argument as
well as the void* return and saves them in a simple linked list.

A call to size(void *p) trips through the linked list looking for
the vallue of p and returns the size of the allocation if found,
else 0. Perfect.

Of course, I wrap free(void *p) as well. We trip through the list
looking for p and freeing it if we find it and removing p's node
from the list. Of course, if we don't find p in the list, we do nothing.

That's when it struck me, I can pass anything to free() and if it's
not found in the list, nothing happens. No danger.
So, if you call free() the node is removed from the linklist then and
there ?
Else, you might call free again on a freed pointer !! as in your freeall()
call
I added another function, 'void freeall(void);' to trip through the
list, freeing the allocations and the list nodes themselves, maybe
just before exiting your program.

--
Joe Wright mailto:jo********@comcast.net
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---

Nov 14 '05 #48
Ravi Uday wrote:
"Joe Wright" <jo********@comcast.net> wrote in message
news:ut********************@comcast.com...
Flash Gordon wrote:

[ snip ]

I never know where (or whether) to enter these incredible threads
but I do have something to share on the Subject.

Some time ago I determined to add 'size_t size(void *);' to my
otherwise meager bag of tricks.

In the simplist case, a call to malloc() is directed to a wrapper
that actually calls malloc but 'remembers' the size_t argument as
well as the void* return and saves them in a simple linked list.

A call to size(void *p) trips through the linked list looking for
the vallue of p and returns the size of the allocation if found,
else 0. Perfect.

Of course, I wrap free(void *p) as well. We trip through the list
looking for p and freeing it if we find it and removing p's node
from the list. Of course, if we don't find p in the list, we do nothing.

That's when it struck me, I can pass anything to free() and if it's
not found in the list, nothing happens. No danger.

So, if you call free() the node is removed from the linklist then and
there ?


Exactly. The allocated memory is freed and then the node is removed
from the list and its memory is freed.
Else, you might call free again on a freed pointer !! as in your freeall()
call


No danger. free(p) first looks up p in the list. If p is not in the
list, nothing is done.
I added another function, 'void freeall(void);' to trip through the
list, freeing the allocations and the list nodes themselves, maybe
just before exiting your program.

--
Joe Wright mailto:jo********@comcast.net
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 14 '05 #49
Joe Wright wrote:
No danger. free(p) first looks up p in the list.
If p is not in the list, nothing is done.


That's completely wrong, Joe.
Please help me debug my_program, it crashes.

/* BEGIN my_program.c */

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
char *pointer = malloc(1);

if (pointer == NULL) {
puts("wow");
} else {
free(pointer);
free(pointer);
}
puts("OK");
return 0;
}

/* END my_program.c */

--
pete
Nov 14 '05 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Tron Thomas | last post by:
As part of applying for a programming position at a company, I recently I had submitted some code samples to one of the developers for review. This is the feedback I received: One of his...
46
by: sbayeta | last post by:
Hi, I'd like to know who is responsible of memory recycling and defragmentation in a C/C++ program, assuming all the memory allocation/deallocation is done using malloc/free or new/delete. ...
25
by: MC | last post by:
Hi I have the following piece of code. int *p; p = malloc(10); int *j; j = p; free(p); Is this legal ? will j still point to the same
13
by: lovecreatesbeauty | last post by:
/* How do free() know how many elements should be freed in a dynamic array? When free a single variable, the amount of byte of memory can be retrieved from the type of variable itself. ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.