473,511 Members | 14,825 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Just how delicate are freed pointers?

Is the following code safe?

SomeType *a, *b;

/* Some code.... */

free(a);

if ( a == b ) b = NULL;

a = NULL;

Thanks.

--
David Scarlett

dscarlett@_ _ _ _ _ _ _ _
_ _ _ _ _ optusnet.com.au
Nov 14 '05 #1
73 2402
David Scarlett wrote:

Is the following code safe?
No.
SomeType *a, *b;

/* Some code.... */

free(a);

if ( a == b ) b = NULL;

a = NULL;


SomeType *a, *b;

/* Some code.... */

if ( a == b ) b = NULL;

free(a);

a = NULL;

--
pete
Nov 14 '05 #2
On Sun, 16 May 2004 03:25:21 GMT, pete <pf*****@mindspring.com> wrote:
David Scarlett wrote:

Is the following code safe?
No.


Hmmm. Assuming a was valid before the free() and b still is at the
point of the comparison, I don't get why you think this is unsafe.
Personally, it seems strange to test the value of a pointer after it
has been freed (and your version is more conventional in that sense),
but since we're only testing the /pointer/ and not trying to access
the memory it is pointing to, why wouldn't the OP's code be "safe"?
-leor
SomeType *a, *b;

/* Some code.... */

free(a);

if ( a == b ) b = NULL;

a = NULL;


SomeType *a, *b;

/* Some code.... */

if ( a == b ) b = NULL;

free(a);

a = NULL;


Nov 14 '05 #3
David Scarlett wrote:
Is the following code safe?
No.
SomeType *a, *b;

/* Some code.... */

free(a);
The standard does not specify whether a is changed. It might still
contain the same value, it might be set to NULL, or it might be some
other damn value.

if ( a == b ) b = NULL;
Pretty pointless comparison, huh?

a = NULL;

Thanks.

Nov 14 '05 #4
In article <r3********************************@4ax.com>,
Leor Zolman <le**@bdsoft.com> wrote:

SNIP....

Hmmm. Assuming a was valid before the free() and b still is at the
point of the comparison, I don't get why you think this is unsafe.
Personally, it seems strange to test the value of a pointer after it
has been freed (and your version is more conventional in that sense),
but since we're only testing the /pointer/ and not trying to access
the memory it is pointing to, why wouldn't the OP's code be "safe"?
-leor

Because on some machine architectures, pointers may be validated
at the time that they are loaded into a machine register instead
of being validated each time they attempt to access memory. Therefore
attempting to access the value of a pointer after it is freed invokes
undefined behaivor.

Nov 14 '05 #5
John Cochran wrote:

(snip)
Because on some machine architectures, pointers may be validated
at the time that they are loaded into a machine register instead
of being validated each time they attempt to access memory. Therefore
attempting to access the value of a pointer after it is freed invokes
undefined behaivor.


You mean like on x86?

Most compilers I know compare pointers without loading them
into segment registers. (I don't remember that there are
instructions for comparing them.) For pointer assignment I
believe it is also usual not to load them into segment registers.

There might be machines, though, that disallowed such operations,
so it is a reasonable restriction.

-- glen

Nov 14 '05 #6
Martin Ambuhl <ma*****@earthlink.net> wrote in news:2go6qiF4ucmjU1@uni-
berlin.de :
The standard does not specify whether a is changed. It might still
contain the same value, it might be set to NULL, or it might be some
other damn value.


How it be changed if free() accepts the value of a, not the address?
--
David Scarlett

dscarlett@_ _ _ _ _ _ _ _
_ _ _ _ _ optusnet.com.au
Nov 14 '05 #7
Martin Ambuhl <ma*****@earthlink.net> writes:
David Scarlett wrote:
Is the following code safe?


No.
SomeType *a, *b;
/* Some code.... */
free(a);


The standard does not specify whether a is changed. It might still
contain the same value, it might be set to NULL, or it might be some
other damn value.


I would argue that the representation of a cannot be changed by the
call to free, since a is passed by value. (It's also been argued that
a sufficiently clever implementation could modify a, but I'm not
convinced; in any case, it shouldn't matter for reasonable code.)

The problem is that the value of a, which was valid before the call,
may become a trap representation after the call (what changes isn't
the value, but the set of values that are considered trap
representations). As a result, accessing the value of a, even just to
compare it, invokes undefined behavior. (In most real-world
implementations, the effect would be harmless, but probably not
particularly useful.)

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

"Martin Ambuhl" <ma*****@earthlink.net> wrote in message
SomeType *a, *b;

/* Some code.... */

free(a);


if ( a == b ) b = NULL;


Pretty pointless comparison, huh?

A points to an allocated block, b points to a block somewhere. If we free
the block that a and b both point to we want to set both to NULL to indicate
that the block is now invalid.
This is perfectly reasonable, and will usually work, but unfortunately isn't
100% portable due to the trap representation problem mentioned elsethread.
Nov 14 '05 #9
In article <Xn***********************@211.29.133.50>,
David Scarlett <lo**@my.signature> wrote:
Martin Ambuhl <ma*****@earthlink.net> wrote in news:2go6qiF4ucmjU1@uni-
berlin.de :
The standard does not specify whether a is changed. It might still
contain the same value, it might be set to NULL, or it might be some
other damn value.


How it be changed if free() accepts the value of a, not the address?


For example, because on some implementation before the call to free () a
was a pointer to allocated memory, consisting of a valid segment and an
offset, and after the call to free () the operating system has
deallocated the segment, and a now consists of an invalid segment and a
meaningless offsets. Even though the bits of a haven't changed, what
used to be a valid pointer is now an invalid pointer.

There are also C interpreters, and with an interpreter I might expect
that every single access to a pointer does check the pointer for
validity.
Nov 14 '05 #10
Keith Thompson wrote:

Martin Ambuhl <ma*****@earthlink.net> writes:
David Scarlett wrote:
Is the following code safe?


No.
SomeType *a, *b;
/* Some code.... */
free(a);


The standard does not specify whether a is changed. It might still
contain the same value, it might be set to NULL, or it might be some
other damn value.


I would argue that the representation of a cannot be changed by the
call to free, since a is passed by value. (It's also been argued that
a sufficiently clever implementation could modify a, but I'm not
convinced; in any case, it shouldn't matter for reasonable code.)

The problem is that the value of a, which was valid before the call,
may become a trap representation after the call (what changes isn't
the value, but the set of values that are considered trap
representations). As a result, accessing the value of a, even just to
compare it, invokes undefined behavior. (In most real-world
implementations, the effect would be harmless, but probably not
particularly useful.)


The OP's original code is fine, although a
little convoluted about the order of operations.

The value of `a' will _not_ be changed by the
compiler, the C standard, _any_ remotely conforming
implementation of `free()' or the architecture
(x86, Sparc, Power PC, etc.) the code is run under.

You can do anything you want with the value of
`a' with the following restrictions:

1. You cannot use it as a value to the `free()'
function again,
2. You cannot de-reference it.

Naturally, the above apply to the `free()'d
_pointer value_ `a' contains. If `a' is given
another valid pointer value (one way of which
is to assign the return of a successful `malloc()'
to it), then the above restrictions are removed.

I think the OP was trying to communicate (and I
may be wrong) (error checking removed for clarity) -

{
SomeType *a, *b;

a = malloc(SomeSize);
b = a;

/* Some stuff involving a & b */

/* We're done with a, free it */
free(a);
a = NULL; /* NULLify it */

/* Oh, and BTW, if `b' still pointed to
the same object as `a', NULLify it too */
if (a == b) {
b = NULL;
}
}

The above example is pretty clean, but in
complex code, it's possible `a' might be
`free()'d from more than one place. To
keep things simple, setting the pointer
NULL at each `free()' point helps in the
prevention of `free()'ing the pointer twice
(since it's perfectly legal to pass a NULL
pointer to `free()'). In the case of `b',
at the point where `a' was `free()'d, `b'
may contain another valid pointer _different_
from `a' (through the program's logic),
and thus is only set to NULL if its value
still matched `a's (because `a's is now invalid).
Stephen
Nov 14 '05 #11
On Sat, 15 May 2004 23:51:41 -0400, Martin Ambuhl wrote:
The standard does not specify whether a is changed. It might still
contain the same value, it might be set to NULL, or it might be some
other damn value.


And a damn value would presumably invoke those nasal demons, no?

;)

(And on the DS9000, it opens the gates to Hell and calls forth Admiral
Hopper to forcibly rewrite your complete code library in COBOL.)

--
yvoregnevna gjragl-guerr gjb-gubhfnaq guerr ng lnubb qbg pbz
To email me, rot13 and convert spelled-out numbers to numeric form.
"Makes hackers smile" makes hackers smile.

Nov 14 '05 #12
Leor Zolman wrote:

On Sun, 16 May 2004 03:25:21 GMT, pete <pf*****@mindspring.com> wrote:
David Scarlett wrote:

Is the following code safe?


No.


Hmmm. Assuming a was valid before the free() and b still is at the
point of the comparison, I don't get why you think this is unsafe.
Personally, it seems strange to test the value of a pointer after it
has been freed (and your version is more conventional in that sense),
but since we're only testing the /pointer/ and not trying to access
the memory it is pointing to, why wouldn't the OP's code be "safe"?
-leor


N869
7.20.3 Memory management functions
[#1]
The value of a pointer
that refers to freed space is indeterminate.

--
pete
Nov 14 '05 #13
"Stephen L." <sd*********@cast-com.net> wrote in
news:40***************@cast-com.net :
I think the OP was trying to communicate (and I
may be wrong) (error checking removed for clarity) -
Close...
a = NULL; /* NULLify it */

/* Oh, and BTW, if `b' still pointed to
the same object as `a', NULLify it too */
if (a == b) {
b = NULL;
}


No point in testing here, as 'a' was changed to NULL immediately before
the test...
--
David Scarlett

dscarlett@_ _ _ _ _ _ _ _
_ _ _ _ _ optusnet.com.au
Nov 14 '05 #14

"Stephen L." <sd*********@cast-com.net> wrote in message
The OP's original code is fine, although a
little convoluted about the order of operations.

The value of `a' will _not_ be changed by the
compiler, the C standard, _any_ remotely conforming
implementation of `free()' or the architecture
(x86, Sparc, Power PC, etc.) the code is run under.

You can do anything you want with the value of
`a' with the following restrictions:

1. You cannot use it as a value to the `free()'
function again,
2. You cannot de-reference it.

You should read a thread before responding.
As others have pointed out, this is true for the vast majority of
implementations, but some will have trap values that trigger when an invalid
pointer (other than NULL) is used in a calculation. This means that
comparing a to b is illegal, as is incrementing a or doing anything else
with it.

Nov 14 '05 #15
"Malcolm" <ma*****@55bank.freeserve.co.uk> wrote in message
news:c8**********@news6.svr.pol.co.uk...

"Martin Ambuhl" <ma*****@earthlink.net> wrote in message
SomeType *a, *b;

/* Some code.... */

free(a);


if ( a == b ) b = NULL;


Pretty pointless comparison, huh?

A points to an allocated block, b points to a block somewhere. If we free
the block that a and b both point to we want to set both to NULL to indicate
that the block is now invalid.
This is perfectly reasonable, and will usually work, but unfortunately isn't
100% portable due to the trap representation problem mentioned elsethread.


The solution mentioned elsewhere is to nullify
the dangling references (e.g., "b") before
free'ing "a" (the last reference to the allocated
block). Of course, always nullify "a" after returning
from free(a).

======================
SomeType *a = NULL, *b = NULL; /* avoid random initial value */

/* ...Some stuff that plays with a and b... */

if (a == b) b = NULL; /* nullify other dangling reference */
free(a); /* bye bye */
a = NULL; /* nullify last dangling reference */
======================

No possibility of a trap fault when the
references are nullified in the proper
order before freeing the memory.
Nov 14 '05 #16
> Because on some machine architectures, pointers may be validated
at the time that they are loaded into a machine register instead
of being validated each time they attempt to access memory.


I have heard that a lot before, but never ran across such architecture.
Could you at least give me one example?

Let's assume this is the case: is NULL a valid pointer?
I don't think so. It can't be dereferenced.

Yet, it is clearly impossible that the following statement be not valid
or undefined behavior, because 1. it would make pointer programming very
difficult and 2. it would cause havoc in trillions of lines of code
all over the world:

p = NULL;

What do you think? Do you think that the "NULL" pointer is a special
case on the aforementioned architectures and therefore it's still ok
to assign it to some pointer variable?
Nov 14 '05 #17
Malcolm wrote:

"Stephen L." <sd*********@cast-com.net> wrote in message
The OP's original code is fine, although a
little convoluted about the order of operations.

The value of `a' will _not_ be changed by the
compiler, the C standard, _any_ remotely conforming
implementation of `free()' or the architecture
(x86, Sparc, Power PC, etc.) the code is run under.

You can do anything you want with the value of
`a' with the following restrictions:

1. You cannot use it as a value to the `free()'
function again,
2. You cannot de-reference it.
You should read a thread before responding.


I did read the thread.
As others have pointed out, this is true for the vast majority of
implementations, but some will have trap values that trigger when an invalid
pointer (other than NULL) is used in a calculation. This means that
comparing a to b is illegal, as is incrementing a or doing anything else
with it.


Sorry, the above is utter nonsense.

Pointer arithmetic is always legal
no matter what the state of the _value_
of that pointer. This is a fact.

However, when any pointer (containing an
invalid value) is dereferenced, then each
architecture/implementation will behave
differently, sometimes with no error/warning
diagnostic at all (just some odd program
behavior).

It's not clear to me that some posters know
to distinguish the operations of "pointer
arithmetic" and "dereferencing the result"
of such arithmetic...
This is a really dated reference, but is
still interesting reading even today -

http://groups.google.com/groups?q=ai....uva.nl&rnum=4
Stephen
Nov 14 '05 #18
On Sun, 16 May 2004 04:20:01 GMT, jd*@smof.fiawol.org (John Cochran) wrote:
In article <r3********************************@4ax.com>,
Leor Zolman <le**@bdsoft.com> wrote:

SNIP....

Hmmm. Assuming a was valid before the free() and b still is at the
point of the comparison, I don't get why you think this is unsafe.
Personally, it seems strange to test the value of a pointer after it
has been freed (and your version is more conventional in that sense),
but since we're only testing the /pointer/ and not trying to access
the memory it is pointing to, why wouldn't the OP's code be "safe"?
-leor

Because on some machine architectures, pointers may be validated
at the time that they are loaded into a machine register instead
of being validated each time they attempt to access memory. Therefore
attempting to access the value of a pointer after it is freed invokes
undefined behaivor.


I've heard this stated before, and I completely understand that loading a
/garbage/ address into an address register under one of these architectures
is bad ju-ju. What makes me wonder in the case of the OP's scenario,
however, is my (admittedly, perhaps outdated) recollection of how memory
allocation works in the C libraries. Under the last systems where I took
notice of such things, once memory had been obtained from the system (on
Unix, it was via an sbrk() call, I believe), it remained allocated to the
process. So I was thinking in terms of "once hardware-validated, always
hardware-validated" during the run of that process...even on those
sensitive architectures. AFAIK, this may no longer be true on modern
systems, though...anyone care to set me straight?
-leor
--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #19
Stephen L. <sd*********@cast-com.net> wrote:
Malcolm wrote:

"Stephen L." <sd*********@cast-com.net> wrote in message
> The OP's original code is fine, although a
> little convoluted about the order of operations.
>
> The value of `a' will _not_ be changed by the
> compiler, the C standard, _any_ remotely conforming
> implementation of `free()' or the architecture
> (x86, Sparc, Power PC, etc.) the code is run under.
>
> You can do anything you want with the value of
> `a' with the following restrictions:
>
> 1. You cannot use it as a value to the `free()'
> function again,
> 2. You cannot de-reference it.
> You should read a thread before responding. I did read the thread. As others have pointed out, this is true for the vast majority of
implementations, but some will have trap values that trigger when an invalid
pointer (other than NULL) is used in a calculation. This means that
comparing a to b is illegal, as is incrementing a or doing anything else
with it.

Sorry, the above is utter nonsense. Pointer arithmetic is always legal
no matter what the state of the _value_
of that pointer. This is a fact.


Sorry if you don't like it. But if you read the C standard carefully
you will find that after a pointer has been free()ed even _looking_
at its value (and not only dereferencing it) invokes undefined behavior.
We had that discussion I year ago here (actually I guess I was more
or less responsible for getting the thread drifting in that direction)
because I also couldn't imagine that just looking at the value of
a free()ed pointer could be forbidden. But I was proven wrong, of
course. Reading clc can tell you a lot about what you don't know,
even if you think you have seen it all (or at least most of it ;-).
It's the old saying: just because you will get away with it on most
architectures doesn't make it legal.

Regards, Jens
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #20
Guillaume <gr*******@NO-SPAMmail.com> writes:

|> > Because on some machine architectures, pointers may be validated
|> > at the time that they are loaded into a machine register instead
|> > of being validated each time they attempt to access memory.

|> I have heard that a lot before, but never ran across such
|> architecture. Could you at least give me one example?

Some implementations of C on the 80286.

|> Let's assume this is the case: is NULL a valid pointer? I don't
|> think so. It can't be dereferenced.

It is a valid pointer value. That doesn't mean that you can dereference
it. One past the end pointers are also valid pointer values.

|> Yet, it is clearly impossible that the following statement be not
|> valid or undefined behavior, because 1. it would make pointer
|> programming very difficult and 2. it would cause havoc in trillions
|> of lines of code all over the world:

|> p = NULL;

|> What do you think? Do you think that the "NULL" pointer is a special
|> case on the aforementioned architectures and therefore it's still ok
|> to assign it to some pointer variable?

It's up to the implementation, but they must do something to ensure that
loading a NULL pointer will not trigger an exception.

Back when the 80286 was a recent architecture, most of the
implementations I used mapped the page 0 to a page full of 0's, so that
dereferencing the null pointer actually worked. If they did this, of
course, there was no problem copying a null pointer.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Nov 14 '05 #21
"Stephen L." <sd*********@cast-com.net> writes:

|> Malcolm wrote:
|> > "Stephen L." <sd*********@cast-com.net> wrote in message
|> > > The OP's original code is fine, although a little convoluted
|> > > about the order of operations.

|> > > The value of `a' will _not_ be changed by the compiler, the C
|> > > standard, _any_ remotely conforming implementation of `free()'
|> > > or the architecture (x86, Sparc, Power PC, etc.) the code is run
|> > > under.

|> > > You can do anything you want with the value of `a' with the
|> > > following restrictions:

|> > > 1. You cannot use it as a value to the `free()'
|> > > function again,
|> > > 2. You cannot de-reference it.

|> > You should read a thread before responding.

|> I did read the thread.

|> > As others have pointed out, this is true for the vast majority of
|> > implementations, but some will have trap values that trigger when
|> > an invalid pointer (other than NULL) is used in a calculation.
|> > This means that comparing a to b is illegal, as is incrementing a
|> > or doing anything else with it.

|> Sorry, the above is utter nonsense.

It's what the C standard says.

|> Pointer arithmetic is always legal no matter what the state of the
|> _value_ of that pointer. This is a fact.

Not according to the C standard.

[...]

|> It's not clear to me that some posters know to distinguish the
|> operations of "pointer arithmetic" and "dereferencing the result" of
|> such arithmetic...

It's not clear to me that some posters know C, as opposed to the
particular implementations they happen to use today.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Nov 14 '05 #22
James Kanze wrote:

Guillaume <gr*******@NO-SPAMmail.com> writes:

|> > Because on some machine architectures, pointers may be validated
|> > at the time that they are loaded into a machine register instead
|> > of being validated each time they attempt to access memory.

<snip>

Back when the 80286 was a recent architecture, most of the
implementations I used mapped the page 0 to a page full of 0's, so that
dereferencing the null pointer actually worked. If they did this, of
course, there was no problem copying a null pointer.


You are saying (please correct me if I'm wrong) that
copying a pointer containing the NULL value is the
same as dereferencing the pointer...

You're confusing a NULL pointer, that when dereferenced
happens to point to a 0 (your words, not mine), and the
NULL pointer itself - you're treating them identically
in your post! If a pointer happens to _point_ to a 0,
that does not define the pointer as a NULL pointer.
You're also assuming that the value for a NULL pointer
is 0 - it depends on the hardware architecture.
You can google for architectures where a NULL pointer
is not represented by 0.

Copying a pointer, even if its value is the NULL value,
(also known as "pointer arithmethic") is _not_ the
same operation as dereferencing that pointer.

There's an interesting link in one of my other
posts along this subject worth reading.
HTH,

Stephen
Nov 14 '05 #23
"Stephen L." <sd*********@cast-com.net> writes:

|> James Kanze wrote:

|> > Guillaume <gr*******@NO-SPAMmail.com> writes:

|> > |> > Because on some machine architectures, pointers may be
|> > |> > validated at the time that they are loaded into a machine
|> > |> > register instead of being validated each time they attempt
|> > |> > to access memory.

|> <snip>

|> > Back when the 80286 was a recent architecture, most of the
|> > implementations I used mapped the page 0 to a page full of 0's, so
|> > that dereferencing the null pointer actually worked. If they did
|> > this, of course, there was no problem copying a null pointer.

|> You are saying (please correct me if I'm wrong) that copying a
|> pointer containing the NULL value is the same as dereferencing the
|> pointer...

No. I'm saying that at the time, most implementations allowed
dereferencing a null pointer, and that of course, if you support
dereferencing it (as an extension), then you can obviously copy it
(which the standard requires).

|> You're confusing a NULL pointer, that when dereferenced
|> happens to point to a 0 (your words, not mine), and the
|> NULL pointer itself - you're treating them identically
|> in your post!

I'm not confusing anything. I'm just explaining what happened on some
particular implementations I once used.

|> If a pointer happens to _point_ to a 0,
|> that does not define the pointer as a NULL pointer.

If the implementation defines all bits to zero as the representation of
a null pointer, then it does. That happened to be the case in the
implementation in question.

I'm aware that this isn't always the case, but the exception is rare
enough that I would have mentionned it had this been the case.

|> You're also assuming that the value for a NULL pointer is 0 - it
|> depends on the hardware architecture. You can google for
|> architectures where a NULL pointer is not represented by 0.

I am aware of architectures where the null pointer is not represented by
all bits being 0. (The integral constant 0 IS a null pointer. Always.
But I'm pretty sure that this isn't what you are trying to say.) I've
even programmed on some, although not in C.

To be clearer, on the implementations I used in the early 80's (when the
80286 was around), the implementation made a conscious decision to allow
dereferencing null pointers. It was a frequent case -- much of the
original software for Unix at the time counted on it, that NULL behaved
like "", for example. The standard decided not to support this use;
even Kernighan and Richie said it was wrong. But it happened to work in
Unix version 6 and version 7, and a lot of software was written which
counted on it. (I happened to be present when we suppressed this
"feature" in our Unix port, by modifying the kernel so that the page 0
was never mapped. We had to back out of the modification, because many
of the Unix toolkit started core dumping on us, and we didn't have time
to correct them before that release.)

|> Copying a pointer, even if its value is the NULL value, (also known
|> as "pointer arithmethic") is _not_ the same operation as
|> dereferencing that pointer.

I never said it was. You have to be able to read the pointer to be able
to do either; there are pointers which you cannot read, and there are
pointers which you can read, but cannot dereference (null pointers and
one past the end pointer).

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Nov 14 '05 #24
> Some implementations of C on the 80286.

Ok, I seem to remember the "selector" scheme and the descriptor tables
for the protected mode of 80x286 and above.

Loading an undefined selector in a selector register could indeed raise
an exception, although most compilers's implementations I have known
would bypass this exception either by masking it or by silently handling
it at run-time. Some other implementations would perform some
computation on pointers before actually loading a selector register,
insuring that it was a valid one beforehand.

Thus, I haven't ever seen an implementation on which assigning an
undefined "address" to a pointer would raise an exception. But of
course, there might have been some. I have looked in the C99 standard
and haven't really found a definite answer on potential problems
with assigning pointers, though. If you find the appropriate section,
feel free to point me to it.

Nov 14 '05 #25
pete wrote:
David Scarlett wrote:
Is the following code safe?

No.

SomeType *a, *b;

/* Some code.... */

free(a);

if ( a == b ) b = NULL;

a = NULL;

SomeType *a, *b;

/* Some code.... */

if ( a == b ) b = NULL;


In case b had been allocated sometime before in the same function,
then this is a potential memory leak

free(a);

a = NULL;

// This is fine.

--
Karthik.
Humans please 'removeme_' for my real email.
Nov 14 '05 #26

On Sun, 16 May 2004, Karthik wrote:

pete wrote:

SomeType *a, *b;

/* Some code.... */

if ( a == b ) b = NULL;


In case b had been allocated sometime before in the same function,
then this is a potential memory leak


Of course it isn't. A memory leak is when you lose all pointers
to an allocated block of memory. (Hint: if a equals b, then a has
the same value as b.)

-Arthur

Nov 14 '05 #27
In article <40***************@cast-com.net>,
"Stephen L." <sd*********@cast-com.net> wrote:
Keith Thompson wrote:

Martin Ambuhl <ma*****@earthlink.net> writes:
David Scarlett wrote:
> Is the following code safe?

No.

> SomeType *a, *b;
> /* Some code.... */
> free(a);

The standard does not specify whether a is changed. It might still
contain the same value, it might be set to NULL, or it might be some
other damn value.


I would argue that the representation of a cannot be changed by the
call to free, since a is passed by value. (It's also been argued that
a sufficiently clever implementation could modify a, but I'm not
convinced; in any case, it shouldn't matter for reasonable code.)

The problem is that the value of a, which was valid before the call,
may become a trap representation after the call (what changes isn't
the value, but the set of values that are considered trap
representations). As a result, accessing the value of a, even just to
compare it, invokes undefined behavior. (In most real-world
implementations, the effect would be harmless, but probably not
particularly useful.)


The OP's original code is fine, although a
little convoluted about the order of operations.

The value of `a' will _not_ be changed by the
compiler, the C standard, _any_ remotely conforming
implementation of `free()' or the architecture
(x86, Sparc, Power PC, etc.) the code is run under.

You can do anything you want with the value of
`a' with the following restrictions:

1. You cannot use it as a value to the `free()'
function again,
2. You cannot de-reference it.


Interesting that you quote a post that explains quite nicely _why_
accessing "a" after "free (a)" is wrong, and then you say it is ok.
Well, it is not. You will mostly get away with it in this case, but it
is wrong. It will go wrong in the following cases, and perhaps in
others:

1. Unusual hardware.
2. C interpreter.
3. Brutally optimising C compiler.
Nov 14 '05 #28
In article <40***********@mindspring.com>,
pete <pf*****@mindspring.com> wrote:
Leor Zolman wrote:

On Sun, 16 May 2004 03:25:21 GMT, pete <pf*****@mindspring.com> wrote:
David Scarlett wrote:
>
> Is the following code safe?

No.


Hmmm. Assuming a was valid before the free() and b still is at the
point of the comparison, I don't get why you think this is unsafe.
Personally, it seems strange to test the value of a pointer after it
has been freed (and your version is more conventional in that sense),
but since we're only testing the /pointer/ and not trying to access
the memory it is pointing to, why wouldn't the OP's code be "safe"?
-leor


N869
7.20.3 Memory management functions
[#1]
The value of a pointer
that refers to freed space is indeterminate.


So the correct thing for a compiler to do after call "free (a)" would be
to treat a the same as an uninitialised variable (uninitialised
variables have indeterminate values as well), giving a warning when you
try to use it and so on.
Nov 14 '05 #29
In article <40*********************@news.club-internet.fr>,
Guillaume <gr*******@NO-SPAMmail.com> wrote:
Because on some machine architectures, pointers may be validated
at the time that they are loaded into a machine register instead
of being validated each time they attempt to access memory.


I have heard that a lot before, but never ran across such architecture.
Could you at least give me one example?

Let's assume this is the case: is NULL a valid pointer?
I don't think so. It can't be dereferenced.

Yet, it is clearly impossible that the following statement be not valid
or undefined behavior, because 1. it would make pointer programming very
difficult and 2. it would cause havoc in trillions of lines of code
all over the world:

p = NULL;

What do you think? Do you think that the "NULL" pointer is a special
case on the aforementioned architectures and therefore it's still ok
to assign it to some pointer variable?


It's very simple: The C Standard says that the value of a after free (a)
is indeterminate (except when a was a null pointer; in that case it is
still a null pointer). That has a very specific meaning; it means that
any use of the value leads to undefined behavior. On the other hand, a
null pointer is _not_ an indeterminate value. It can be used legally in
many situations, like assignment, comparison with == or != (but not with
<=, for example).

When the C Standard says it is indeterminate it is quite pointless to
think what hardware could do what kind of strange things. You just need
an optimising compiler which may assume that your code doesn't invoke
undefined behavior, and therefore can make any kind of assumptions.

For example, after calling free (a) any use of a is undefined behavior
unless a was a null pointer. Therefore if you use a after calling free
(a) an optimising compiler may assume that a is a null pointer. So if
you compare a == b after calling free (a), the compiler can change this
to b == NULL.
Nov 14 '05 #30
In article <40***************@cast-com.net>,
"Stephen L." <sd*********@cast-com.net> wrote:
Malcolm wrote:

"Stephen L." <sd*********@cast-com.net> wrote in message
The OP's original code is fine, although a
little convoluted about the order of operations.

The value of `a' will _not_ be changed by the
compiler, the C standard, _any_ remotely conforming
implementation of `free()' or the architecture
(x86, Sparc, Power PC, etc.) the code is run under.

You can do anything you want with the value of
`a' with the following restrictions:

1. You cannot use it as a value to the `free()'
function again,
2. You cannot de-reference it.

You should read a thread before responding.


I did read the thread.
As others have pointed out, this is true for the vast majority of
implementations, but some will have trap values that trigger when an
invalid
pointer (other than NULL) is used in a calculation. This means that
comparing a to b is illegal, as is incrementing a or doing anything else
with it.


Sorry, the above is utter nonsense.

Pointer arithmetic is always legal
no matter what the state of the _value_
of that pointer. This is a fact.


This is not a fact, this is ignorance and bullshit. Go and buy yourself
a copy of the C Standard; you can find it at www.ansi.com for $18.
Nov 14 '05 #31
In article <40*********************@news.club-internet.fr>,
Guillaume <gr*******@NO-SPAMmail.com> wrote:
Some implementations of C on the 80286.


Ok, I seem to remember the "selector" scheme and the descriptor tables
for the protected mode of 80x286 and above.

Loading an undefined selector in a selector register could indeed raise
an exception, although most compilers's implementations I have known
would bypass this exception either by masking it or by silently handling
it at run-time. Some other implementations would perform some
computation on pointers before actually loading a selector register,
insuring that it was a valid one beforehand.

Thus, I haven't ever seen an implementation on which assigning an
undefined "address" to a pointer would raise an exception. But of
course, there might have been some. I have looked in the C99 standard
and haven't really found a definite answer on potential problems
with assigning pointers, though. If you find the appropriate section,
feel free to point me to it.


If you use any variable with an indeterminate value, then you get
undefined behavior. At that point, _anything_ can happen. Good
optimising compilers will also make optimisations based on the
assumption that your code doesn't invoke undefined behavior; if you make
that assumption wrong then again anything can happen.
Nov 14 '05 #32
>> As others have pointed out, this is true for the vast majority of
implementations, but some will have trap values that trigger when an invalid
pointer (other than NULL) is used in a calculation. This means that
comparing a to b is illegal, as is incrementing a or doing anything else
with it.
Sorry, the above is utter nonsense.

Pointer arithmetic is always legal
no matter what the state of the _value_
of that pointer. This is a fact.


No, it isn't. It is perfectly legal for this code to abort:

#include <stdlib.h>
....
char *a;

a = malloc(1);
a; /* no smegfault here */
free(a);
a; /* smegfault here */

Loading the value of "a" into a register on a segmented platform
(e.g. x86 in 16-bit or 32-bit protected mode, where pointers include
a 16-bit segment number), which includes loading the segment portion
of the pointer into a segment register, can cause a processor trap
if there is no mapping for the segment portion. Notice that I'm
*NOT* dereferencing the pointer.

Few implementations work this way because it's a pain in the butt and
a lot of sloppy code out there won't work. But it's allowed per
ANSI C.
However, when any pointer (containing an
invalid value) is dereferenced, then each
architecture/implementation will behave
differently, sometimes with no error/warning
diagnostic at all (just some odd program
behavior).

It's not clear to me that some posters know
to distinguish the operations of "pointer
arithmetic" and "dereferencing the result"
of such arithmetic...


The point here is that both pointer arithmetic and dereferencing
the result can *BOTH* cause the same undefined behavior. Or
perhaps different undefined behavior.

Gordon L. Burditt
Nov 14 '05 #33
Christian Bau wrote:
.... snip ...
For example, after calling free (a) any use of a is undefined
behavior unless a was a null pointer. Therefore if you use a
after calling free (a) an optimising compiler may assume that
a is a null pointer. So if you compare a == b after calling
free (a), the compiler can change this to b == NULL.


Splutter. Hogwash. Bullshit. Merde. Schiesse. :-) I think
you mean that such a change is one of the many undefined
behaviours available.

--
"I'm a war president. I make decisions here in the Oval Office
in foreign policy matters with war on my mind." - Bush.
"Churchill and Bush can both be considered wartime leaders, just
as Secretariat and Mr Ed were both horses." - James Rhodes.
Nov 14 '05 #34
> If you use any variable with an indeterminate value, then you get
undefined behavior.


I find this statement highly ambiguous.
Nov 14 '05 #35
Guillaume <gr*******@NO-SPAMmail.com> writes:

|> > Some implementations of C on the 80286.

|> Ok, I seem to remember the "selector" scheme and the descriptor
|> tables for the protected mode of 80x286 and above.

|> Loading an undefined selector in a selector register could indeed
|> raise an exception, although most compilers's implementations I have
|> known would bypass this exception either by masking it or by
|> silently handling it at run-time. Some other implementations would
|> perform some computation on pointers before actually loading a
|> selector register, insuring that it was a valid one beforehand.

|> Thus, I haven't ever seen an implementation on which assigning an
|> undefined "address" to a pointer would raise an exception. But of
|> course, there might have been some. I have looked in the C99
|> standard and haven't really found a definite answer on potential
|> problems with assigning pointers, though. If you find the
|> appropriate section, feel free to point me to it.

The most efficient way to copy a pointer on a 80286 would be:

LES AX,ptrSource
MOV ptrDest,AX
MOV ptrDest+2,ES

I've seen compilers which did this, although I forget off hand which
ones. (The Intel compilers, maybe?)

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Nov 14 '05 #36
(I removed the referent for the first "this" pronoun below, but I
think the idea still comes through.)

In article <news:1k********************************@4ax.com >
Leor Zolman <le**@bdsoft.com> writes:
I've heard this stated before, and I completely understand that loading a
/garbage/ address into an address register under one of these architectures
is bad ju-ju.
Correct.
What makes me wonder in the case of the OP's scenario, however, is
my (admittedly, perhaps outdated) recollection of how memory
allocation works in the C libraries.
The C standards do not dictate how the underlying implementation
has to work -- so "how it works" underneath (whether past or present)
is at best a guideline.
Under the last systems where I took notice of such things, once
memory had been obtained from the system (on Unix, it was via an
sbrk() call, I believe), it remained allocated to the process.
Generally true. But these days some Unix and Unix-like systems
have effectively removed sbrk() entirely (there is always some
compatibility module of course), preferring to use mmap() to obtain
"anonymous" (swap-device-backed) virtual memory. The advantages
are that the memory need not be contiguous, can be mapped with
varying permissions -- various data areas might be marked "read-only
yet executable" or "read/write and *not* executable" -- and can be
altered or returned to the OS piecemeal if desired.
So I was thinking in terms of "once hardware-validated, always
hardware-validated" during the run of that process...even on those
sensitive architectures. AFAIK, this may no longer be true on modern
systems, though...anyone care to set me straight?


Suppose, then, you have a hardware architecture that verifies some
part(s) of a pointer, and a C support library in which, in at least
some cases, free() hands underlying page(s) back to the OS, which
then revokes all access. In this case, the bits stored in a pointer
"pre-free" represent a valid location, while those same bits stored
in the same pointer "post-free" no longer represent a valid location.

If the pointer-verification operation is performed on simple pointer
comparisons and copies, such comparisons and copies will indeed
trap the now-illegal value:

char *a, *b;
...
a = malloc(N);
b = a;
...
free(a);
if (a == b) ... /* invalid */
/* or */
b = a; /* invalid */

If the pointer-verification operation is applied to pointer-following
operations, things like:

free(a);
use(*a); /* invalid */

will trap. This "dereference trap" is considerably more common,
and is available on a number of Unix-like systems that use mmap()
and have "debug" versions of malloc() and free().

The C standards permit the pointer-verification step to occur
at any or all of these places. Most implementations, for various
good reasons, only do the last one -- but at least for debugging
purposes, the earlier verifications could also be useful. Even
on hardware that does not provide such verification automatically,
the compiler could insert "verify" steps for you.
--
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 #37
On Sun, 16 May 2004 11:42:24 GMT, pete <pf*****@mindspring.com> wrote:
Leor Zolman wrote:

On Sun, 16 May 2004 03:25:21 GMT, pete <pf*****@mindspring.com> wrote:
>David Scarlett wrote:
>>
>> Is the following code safe?
>
>No.


Hmmm. Assuming a was valid before the free() and b still is at the
point of the comparison, I don't get why you think this is unsafe.
Personally, it seems strange to test the value of a pointer after it
has been freed (and your version is more conventional in that sense),
but since we're only testing the /pointer/ and not trying to access
the memory it is pointing to, why wouldn't the OP's code be "safe"?
-leor


N869
7.20.3 Memory management functions
[#1]
The value of a pointer
that refers to freed space is indeterminate.


Ok, thanks! That makes it pretty clear. In the copy of the C99 Standard I
have (ISO/IEC 9899, "Second edition", 1999-12-01) they've moved that to the
last line of 6.2.4/2.

In appendix J.2 ("The behavior is undefined in the following circumstances"
followed by 11 pages of circumstances), I did find this item (page 501):

The value of a pointer that refers to space deallocated by a
call to the free or realloc function is used (7.20.3).

The interesting thing is the reference is back to 7.20.3, where you saw the
statement back in the draft. It looks to me as if they moved the statement
but perhaps forgot to update the note in J.2.
-leor

--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #38
In article <1k********************************@4ax.com>,
Leor Zolman <le**@bdsoft.com> wrote:

SNIP...
I've heard this stated before, and I completely understand that loading a
/garbage/ address into an address register under one of these architectures
is bad ju-ju. What makes me wonder in the case of the OP's scenario,
however, is my (admittedly, perhaps outdated) recollection of how memory
allocation works in the C libraries. Under the last systems where I took
notice of such things, once memory had been obtained from the system (on
Unix, it was via an sbrk() call, I believe), it remained allocated to the
process. So I was thinking in terms of "once hardware-validated, always
hardware-validated" during the run of that process...even on those
sensitive architectures. AFAIK, this may no longer be true on modern
systems, though...anyone care to set me straight?

And I've dealt with a system that one you passed a pointer to free(), the
memory freed was returned to the system as a whole and could then be
allocated to any process that desired memory (the Amiga used this method).
Nov 14 '05 #39
Thanks, Chris. I've now (by Pete) also been pointed to the wording in the
Standard (6.2.4/2) that evidently leaves no wiggle room for allowing /any/
use of a free'd pointer. And it looks like what you've described in your
post would justify that.
-leor
--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #40
On Sun, 16 May 2004 21:56:09 +0100, Christian Bau
<ch***********@cbau.freeserve.co.uk> wrote:
In article <40***********@mindspring.com>,
pete <pf*****@mindspring.com> wrote:
Leor Zolman wrote:
>
> On Sun, 16 May 2004 03:25:21 GMT, pete <pf*****@mindspring.com> wrote:
>
> >David Scarlett wrote:
> >>
> >> Is the following code safe?
> >
> >No.
>
> Hmmm. Assuming a was valid before the free() and b still is at the
> point of the comparison, I don't get why you think this is unsafe.
> Personally, it seems strange to test the value of a pointer after it
> has been freed (and your version is more conventional in that sense),
> but since we're only testing the /pointer/ and not trying to access
> the memory it is pointing to, why wouldn't the OP's code be "safe"?
> -leor


N869
7.20.3 Memory management functions
[#1]
The value of a pointer
that refers to freed space is indeterminate.


So the correct thing for a compiler to do after call "free (a)" would be
to treat a the same as an uninitialised variable (uninitialised
variables have indeterminate values as well), giving a warning when you
try to use it and so on.


As I understand it, violations of things not in a "Constraints" section of
the Standard are not required to draw a diagnostic; compilers are free to
emit or not emit diagnostics as they please (IOW, it is a compiler QOI
issue).

In any case, this sounds more like something that might fall into the
domain of a lint-like program, if anywhere, rather than the compiler.
Consider code such as the following:

char *p, *q, *r;
p = malloc(...);
q = malloc(...);
r = q;
...
free(q);
...
if (p == r ) /* oops, can't test q...er, r! */
...

Would you expect a compiler to be "smart enough" to know that testing r is
actually testing the freed value of q, and warn about it?
-leor

--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #41
On Mon, 17 May 2004 00:35:23 +0200, Guillaume
<gr*******@NO-SPAMmail.com> wrote in comp.lang.c:
If you use any variable with an indeterminate value, then you get
undefined behavior.


I find this statement highly ambiguous.


How so? Both the terms "indeterminate value" and "undefined behavior"
are specifically defined in the standard itself.

And as for a freed pointer, paragraph 2 of section 6.2.4 "Storage
duration of objects" specifically states:

"The value of a pointer becomes indeterminate when the object it
points to reaches the end of its lifetime."

It then refers to section 7.20.3 "Memory management functions" for the
specifics of dynamically allocated objects. This states:

"The lifetime of an allocated object extends from the allocation until
the deallocation."

This makes it quite clear that once a pointer obtained from
malloc/calloc/realloc is passed to free, the pointer's value becomes
indeterminate.

Or do you doubt the connection between the use of objects of
indeterminate value and 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 #42
On Sun, 16 May 2004 12:23:41 -0400, Leor Zolman <le**@bdsoft.com>
wrote in comp.lang.c:
On Sun, 16 May 2004 04:20:01 GMT, jd*@smof.fiawol.org (John Cochran) wrote:
In article <r3********************************@4ax.com>,
Leor Zolman <le**@bdsoft.com> wrote:

SNIP....

Hmmm. Assuming a was valid before the free() and b still is at the
point of the comparison, I don't get why you think this is unsafe.
Personally, it seems strange to test the value of a pointer after it
has been freed (and your version is more conventional in that sense),
but since we're only testing the /pointer/ and not trying to access
the memory it is pointing to, why wouldn't the OP's code be "safe"?
-leor

Because on some machine architectures, pointers may be validated
at the time that they are loaded into a machine register instead
of being validated each time they attempt to access memory. Therefore
attempting to access the value of a pointer after it is freed invokes
undefined behaivor.


I've heard this stated before, and I completely understand that loading a
/garbage/ address into an address register under one of these architectures
is bad ju-ju. What makes me wonder in the case of the OP's scenario,
however, is my (admittedly, perhaps outdated) recollection of how memory
allocation works in the C libraries. Under the last systems where I took
notice of such things, once memory had been obtained from the system (on
Unix, it was via an sbrk() call, I believe), it remained allocated to the
process. So I was thinking in terms of "once hardware-validated, always
hardware-validated" during the run of that process...even on those
sensitive architectures. AFAIK, this may no longer be true on modern
systems, though...anyone care to set me straight?
-leor


There are far more platforms using virtual memory management on modern
processors than just UNIX variants. The point is that at the time
memory is freed, it might very well be unmapped by the memory
management hardware, thus rendering its address invalid.

--
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 #43
In article <40***************@yahoo.com>,
CBFalconer <cb********@yahoo.com> wrote:
Christian Bau wrote:

... snip ...

For example, after calling free (a) any use of a is undefined
behavior unless a was a null pointer. Therefore if you use a
after calling free (a) an optimising compiler may assume that
a is a null pointer. So if you compare a == b after calling
free (a), the compiler can change this to b == NULL.


Splutter. Hogwash. Bullshit. Merde. Schiesse. :-) I think
you mean that such a change is one of the many undefined
behaviours available.


Yes. Too many people are caught in their little world of
x86/PowerPC/Mips/Alpha processor and think that these processors define
the behavior of the C language. That is most definitely not so.

In many cases the result of undefined behavior will be that the compiler
never notices the undefined behavior, translates your code in a natural
way, and the undefined behavior will be whatever the processor does. But
that is by far not the only thing that can happen.

An optimising compiler will make the assumption that your code invokes
no undefined behavior. The compiler is absolutely allowed to do this.
The assumption may be wrong, but any damage done as a result is the
fault of the programmer who invoked undefined behavior, not the fault of
the compiler. Then the compiler can draw any logical conclusions from
the assumption that you invoke no undefined behavior and compile
according to these conclusions.

When you look at the "restrict" specification in C99: What it
essentially says is that "restrict" is now a reserved word, you can
insert the keyword "restrict" into legal code in certain places, and
certain code that had defined behavior has undefined behavior when
"restrict" has been added. So what is "restrict" good for? It allows the
compiler to make assumptions about your code and therefore generate
faster code.
Nov 14 '05 #44
CBFalconer <cb********@yahoo.com> scribbled the following:
Christian Bau wrote:
... snip ...

For example, after calling free (a) any use of a is undefined
behavior unless a was a null pointer. Therefore if you use a
after calling free (a) an optimising compiler may assume that
a is a null pointer. So if you compare a == b after calling
free (a), the compiler can change this to b == NULL.
Splutter. Hogwash. Bullshit. Merde. Schiesse. :-) I think
you mean that such a change is one of the many undefined
behaviours available.


You mean "scheisse". If there is "ei" or "ie" in a German word, you
can depend on native English speakers to spell it wrong. Likewise if
there is "ou" or "uo" in a Finnish word, you can depend on Swedes to
spell it wrong.

--
/-- Joona Palaste (pa*****@cc.helsinki.fi) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"No, Maggie, not Aztec, Olmec! Ol-mec!"
- Lisa Simpson
Nov 14 '05 #45
Christian Bau <ch***********@cbau.freeserve.co.uk> writes:
In article <40***********@mindspring.com>,
pete <pf*****@mindspring.com> wrote:

[...]
N869
7.20.3 Memory management functions
[#1]
The value of a pointer
that refers to freed space is indeterminate.


So the correct thing for a compiler to do after call "free (a)" would be
to treat a the same as an uninitialised variable (uninitialised
variables have indeterminate values as well), giving a warning when you
try to use it and so on.


Quibble:

As far as the standard is concerned, the "correct" thing for a
compiler (for code that references a after calling free(a) is anything
it likes. It's undefined behavior; the standard does not require any
sort of diagnostic.

But yes, a sufficiently clever and friendly compiler might give a
warning. This is a QoI (Quality of Implementation) issue, not a
correctness issue.

--
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 #46
"Stephen L." <sd*********@cast-com.net> wrote in message
news:40***************@cast-com.net...
Malcolm wrote:

"Stephen L." <sd*********@cast-com.net> wrote in message
You can do anything you want with the value of
`a' with the following restrictions:

1. You cannot use it as a value to the `free()'
function again,
2. You cannot de-reference it.
You should read a thread before responding.


I did read the thread.


Actually, you should read the _last_ thread on this, just a few weeks ago.
Then you'd know exactly why you're wrong, including citations from the
Standard.

It's okay to be wrong every now and then, but when someone contradicts
you --especially half a dozen someones -- you might want to double-check
your facts (and provide citations) before asserting you're right and
everyone else is wrong.
As others have pointed out, this is true for the vast majority of
implementations, but some will have trap values that trigger when an invalid pointer (other than NULL) is used in a calculation. This means that
comparing a to b is illegal, as is incrementing a or doing anything else
with it.


Sorry, the above is utter nonsense.


Nope, it's valid on some implementations and allowed by the Standard. See
the previous thread for citations.
Pointer arithmetic is always legal
no matter what the state of the _value_
of that pointer. This is a fact.
Nope. Even examining the value of an invalid pointer is undefined behavior.
It may work on some platforms, but the Standard doesn't guarantee it.
It's not clear to me that some posters know
to distinguish the operations of "pointer
arithmetic" and "dereferencing the result"
of such arithmetic...


It's not clear that you understand the meaning of "undefined behavior" as
applied to examining invalid pointers. Doing arithmetic, checking for
equality, assigning them, and many other operations cause UB, not just
dereferencing.

You are confusing how your platform acts with what the Standard says.
S

--
Stephen Sprunk "Stupid people surround themselves with smart
CCIE #3723 people. Smart people surround themselves with
K5SSS smart people who disagree with them." --Aaron Sorkin

Nov 14 '05 #47
CBFalconer <cb********@yahoo.com> writes:
Christian Bau wrote:

... snip ...

For example, after calling free (a) any use of a is undefined
behavior unless a was a null pointer. Therefore if you use a
after calling free (a) an optimising compiler may assume that
a is a null pointer. So if you compare a == b after calling
free (a), the compiler can change this to b == NULL.


Splutter. Hogwash. Bullshit. Merde. Schiesse. :-) I think
you mean that such a change is one of the many undefined
behaviours available.


Yes, it's one of the many undefined behaviors available, but I think
Christian's statement is correct.

A compiler is allowed to perform transformations based on the
assumption that no undefined behavior occurs. (If no undefined
behavior occurs, the compiler was right, and the transformation is ok;
if undefined behavior does occur, the compile can do anything it
likes.)

So given a function like this:

void func(int *ptr)
{
free(ptr);
if (some_other_ptr == ptr) {
...
}
}

the compiler may replace the comparison "some_other_ptr == ptr" with
"some_other_ptr == NULL". This transformation will not cause any
valid program to misbehave.

(Transforming "some_other_ptr == ptr" to "some_other_ptr == NULL" may
not seem like much of an optimization, but if the compiler knows from
data flow analysis that some_other_ptr is null, or that it isn't, it
can eliminate the comparison altogether).

--
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 #48
Keith Thompson <ks***@mib.org> writes:
[...]
Quibble:

As far as the standard is concerned, the "correct" thing for a
compiler (for code that references a after calling free(a) is anything
it likes. It's undefined behavior; the standard does not require any
sort of diagnostic.


Sloppy proofreading strikes again. What I meant was:

As far as the standard is concerned, the "correct" thing for a
compiler to do (for code that references a after calling free(a)) is
anything it likes. It's undefined behavior; the standard does not
require any sort of diagnostic.

--
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 #49
Stephen Sprunk wrote:
.... snip ...
Nope, it's valid on some implementations and allowed by the
Standard. See the previous thread for citations.


Which is an argument for always using:

#define FREE(x) do {free(x); x = NULL;} while (0)

ensuring we can always use x normally in equality comparisons.

--
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 #50

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

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.