Just how delicate are freed pointers?

D

David Scarlett

Is the following code safe?



SomeType *a, *b;

/* Some code.... */

free(a);

if ( a == b ) b = NULL;

a = NULL;



Thanks.
 
P

pete

David said:
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;
 
L

Leor Zolman


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
 
M

Martin Ambuhl

David said:
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?
 
J

John Cochran

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

glen herrmannsfeldt

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
 
D

David Scarlett

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

Keith Thompson

Martin Ambuhl said:
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.)
 
M

Malcolm

Martin Ambuhl said:
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.
 
C

Christian Bau

David Scarlett said:
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.
 
S

Stephen L.

Keith said:
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
 
A

August Derleth

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

pete

Leor said:
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.
 
D

David Scarlett

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

Malcolm

Stephen L. said:
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.
 
X

xarax

Malcolm said:
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.
 
G

Guillaume

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

Stephen L.

Malcolm said:
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=a...fe=off&[email protected]&rnum=4


Stephen
 
L

Leor Zolman

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.

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
 
J

Jens.Toerring

I did read the thread.
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
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top