malloc()/free() question

C

Chad

I just can't sit down and watch TV or go to the local bar and talk
about what I've done on my days off with the locals. With that.....

Is the following valid?
m-net% more mall.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int main(void)
{
char a = 5;
char *p;

if((p = malloc(sizeof a)) == NULL ){
fprintf(stderr, "Can't allocate memory\n");
}

free(p);

if(p =! NULL){
printf("Memory has been freed\n");
}

return 0;
}
m-net% gcc -Wall mall.c -o mall
mall.c: In function `main':
mall.c:16: warning: assignment makes pointer from integer without a
cast
mall.c:16: warning: suggest parentheses around assignment used as
truth value
m-net% ./mall
Memory has been freed
m-net%
 
I

Ike Naar

if(p =! NULL){

This is equivalent to

if (p = (!NULL)) {

which assigns the value !NULL to p, then checks if p is nonzero.

You probably wanted

if (p != NULL) {

Ike
 
C

Chad

This is equivalent to

if (p = (!NULL)) {

which assigns the value !NULL to p, then checks if p is nonzero.

You probably wanted

if (p != NULL) {

So does check if p is not equal to NULL after free valid or is it
undefined behavior?

Here is the corrected version.

m-net% more mall.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int main(void)
{
char a = 5;
char *p;

if((p = malloc(sizeof a)) == NULL ){
fprintf(stderr, "Can't allocate memory\n");
}

free(p);

if(p != NULL){
printf("Memory has been freed\n");
}

return 0;
}
m-net% gcc -Wall mall.c -o mall
m-net% ./mall
Memory has been freed
m-net%
 
K

Keith Thompson

Chad said:
So does check if p is not equal to NULL after free valid or is it
undefined behavior?
[snip]

It's undefined behavior. Once you pass a non-null pointer to free(),
that pointer's value becomes indeterminate. Attempting to refer to
that value, even without dereferencing it, invokes undefined behavior.

On most systems, there will be no visible symptoms. But consider a
system that has special registers for pointers/addresses, where
loading a value into an address register implicitly checks its
validity, and causes a trap if it's invalid. Calling free() could
update the system's memory map so that, even though the pointer
contains the same address that it did before, that address is no
longer valid. Kaboom.

I don't know whether such a system actually exists, but the standard
is designed to permit it.

In any case, checking the value of a pointer after free()ing it won't
do you much good. If the pointer was null before calling free(), it
will still be null, since free(NULL) has no effect. If it was
non-null, it will still be non-null (ignoring the undefined behavior
issue). free(), like any other function, cannot modify the value of
its argument.

Note also that free() has no mechanism to report success or failure.
Either you give it a null pointer (and it does nothing), or you give
it a valid pointer that can be freed (in which case it *must*
succeesfully free it; if not, the implementation is broken), or you
give it an invalid pointer (in which case the behavior is undefined,
and your program is broken). You just have to be careful.
 
I

Ike Naar

So does check if p is not equal to NULL after free valid or is it
undefined behavior?

Here is the corrected version.
[snip]

free(p);

if(p != NULL){

The check is not valid.
p is indeterminate after free(p) .

Ike
 
R

Richard

Keith Thompson said:
Chad said:
So does check if p is not equal to NULL after free valid or is it
undefined behavior?
[snip]

It's undefined behavior. Once you pass a non-null pointer to free(),
that pointer's value becomes indeterminate. Attempting to refer to
that value, even without dereferencing it, invokes undefined behavior.


I find that absolutely astonishing. So

p=malloc(1);
free(p);
display(p); /* log the address used */

is undefined?
 
H

Harald van Dijk

Keith Thompson said:
Chad said:
So does check if p is not equal to NULL after free valid or is it
undefined behavior?
[snip]
It's undefined behavior. Once you pass a non-null pointer to free(),
that pointer's value becomes indeterminate. Attempting to refer to
that value, even without dereferencing it, invokes undefined behavior.

I find that absolutely astonishing. So

p=malloc(1);
free(p);
display(p); /* log the address used */

is undefined?

Assuming malloc succeeded, yes, the behaviour is undefined if you do that.
Can you log the address before calling free?
 
R

Richard

Harald van Dijk said:
Keith Thompson said:
So does check if p is not equal to NULL after free valid or is it
undefined behavior?
[snip]
It's undefined behavior. Once you pass a non-null pointer to free(),
that pointer's value becomes indeterminate. Attempting to refer to
that value, even without dereferencing it, invokes undefined behavior.

I find that absolutely astonishing. So

p=malloc(1);
free(p);
display(p); /* log the address used */

is undefined?

Assuming malloc succeeded, yes, the behaviour is undefined if you do that.
Can you log the address before calling free?

yes, of course : it was an example.
 
R

Richard Tobin

Chad said:
free(p);

if(p =! NULL){
printf("Memory has been freed\n");

Ignoring from your syntax error, free() doesn't change the pointer to
indicate that it's been freed. It couldn't possibly, because it's a
function, and arguments are passed by value in C.

-- Richard
 
P

Peter Nilsson

Richard said:
... So

p=malloc(1);
free(p);
display(p); /* log the address used */

is undefined?

The value of p is indeterminate, however the representation
can still be printed (via unsigned char lvalues). This is the
best way to portably print pointers IMO.
 
H

Harald van Dijk

The value of p is indeterminate, however the representation can still be
printed (via unsigned char lvalues).

However, there's no guarantee that two pointer values that compare equal
have identical representations. Usually this won't matter, but if you
expect to be able to compare the representations of two pointers, it will.

Additionally, it has been decided that once the value becomes
indeterminate, the representation also becomes indeterminate. Quoting part
of the response to DR #260:

"Values may have any bit-pattern that validly represents them and the
implementation is free to move between alternate representations (for
example, it may normalize pointers, floating-point representations etc.).
In the case of an indeterminate value all bit-patterns are valid
representations and the actual bit-pattern may change without direct
action of the program."

Unfortunately, this response fairly directly contradicts the standard for
reasons already explained in the DR, and as far as I am aware, the text of
the standard has not been updated to support the response, so I'm not sure
of its official status.
This is the best way to portably
print pointers IMO.

Does this have improvements over %p other than the possibility of printing
trap representations?
 
V

vippstar

Ignoring from your syntax error, free() doesn't change the pointer to
indicate that it's been freed. It couldn't possibly, because it's a
function, and arguments are passed by value in C.

There isn't a syntax error, more like a misunderstanding of the
operators.
=! is valid, it's two different tokens/operators = and !
 
V

vippstar

However, there's no guarantee that two pointer values that compare equal
have identical representations. Usually this won't matter, but if you
expect to be able to compare the representations of two pointers, it will..

Additionally, it has been decided that once the value becomes
indeterminate, the representation also becomes indeterminate. Quoting part
of the response to DR #260:

"Values may have any bit-pattern that validly represents them and the
implementation is free to move between alternate representations (for
example, it may normalize pointers, floating-point representations etc.)..
In the case of an indeterminate value all bit-patterns are valid
representations and the actual bit-pattern may change without direct
action of the program."

Unfortunately, this response fairly directly contradicts the standard for
reasons already explained in the DR, and as far as I am aware, the text of
the standard has not been updated to support the response, so I'm not sure
of its official status.
<snip>

I'm confused about this. (DR?)
When the value is indeterminate, what happends to the representation?
What about this:

int foo; /* no initialization */
/* here use ((unsigned char *)&foo)[0 to sizeof foo - 1], possible? */
 
C

Chris Torek

Indeed, this seems bogus given that elsewhere the Standard assures
us that we can use "unsigned char *" to peek at representations.

If the DR said "the representation may change when copied by any
means other than direct use of unsigned char *", that would be
another matter entirely. This is the sort of thing that happens
with floating-point bit patterns, for instance: if you have, say,
a float "f" whose representation represents some sort of invalid
value, and you do "float g = f;", this may write a *different*
invalid-value representation into g, particularly if exceptions
are currently disabled.

(Of course, a real system may "copy" these things unexpectedly,
e.g., due to process time-slicing and/or migration, so perhaps the
copy can happen with no C code involved. If this changes a
representation, that would make it look as though the representation
changed spontaneously.)

I'm confused about this. (DR?)
When the value is indeterminate, what happends to the representation?

In general, I would say "nothing". Clearly the DR above says
otherwise.
What about this:

int foo; /* no initialization */
/* here use ((unsigned char *)&foo)[0 to sizeof foo - 1], possible? */

The Standard guarantees that we can use them; it just tells us
nothing about what we will see if and when we do so.
 
V

vippstar

In general, I would say "nothing". Clearly the DR above says
otherwise.

What is the DR? Sorry if that's a silly question but I can't think of
anything meaningful for "DR". If I understand correctly, peeking at
the representation with unsigned char is allowed. I'm surprised.
What about this:
int foo; /* no initialization */
/* here use ((unsigned char *)&foo)[0 to sizeof foo - 1], possible? */

The Standard guarantees that we can use them; it just tells us
nothing about what we will see if and when we do so.

That is also very weird.
Then is this valid?

unsigned char c, ch;
ch = c;

Assuming this is not valid, isn't it the same case with my other
example? (with foo)
 
V

vippstar

I'm confused about this. (DR?)
When the value is indeterminate, what happends to the representation?

The representation might not change, which does not prevent it from
causing traps when used even if it didn't before. (Does the number
on your credit card change if you don't pay the bill and they cancel
it?) The memory page to which it refers might be now marked as
nonexistent in whatever memory management hardware the system has.
What about this:
int foo; /* no initialization */
/* here use ((unsigned char *)&foo)[0 to sizeof foo - 1], possible? */

Since you are accessing it as unsigned char, it shouldn't trap.
What values you get is another issue.


Who are you talking to?
 
V

vippstar

(e-mail address removed) writes:

[...]> What is the DR? Sorry if that's a silly question but I can't think of
anything meaningful for "DR". If I understand correctly, peeking at
the representation with unsigned char is allowed. I'm surprised.

[...]

A DR is a Defect Report, basically a bug report against the Standard.
You can see the C99 DRs at
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm>.

I think the particular DR being discussed here is #260.

Ah, now it does make more sense, thanks. However, I think you snipped
a little too much from my message.
The second sentence says I'm surprised that it's possible to peek at
the representation. I was talking about a previous message and
indeterminate values.

Though my other question still stands, is
unsigned char c, ch; c = ch;
valid?
 
V

vippstar

(e-mail address removed) said:



Whilst pete's answer is perfectly correct, it leaves an important question
unasked, let alone unanswered.

Never mind whether the code is "valid", in the sense that it mustn't cause
a crash or something of that kind. Rather, ask what the code *means*, in
terms of the problem domain. I can think of no sensible answer to that
question.

I'm sorry, I don't understand your question. "Problem domain"? Do you
mean how my question is related to the original question? I'm not sure
how, but I came up with it and I thought I should ask. Or do you mean
"why would one want to do that"? In that case, I was really just
wondering whether it is valid or not.
 
R

Ron Ford

What is the DR? Sorry if that's a silly question but I can't think of
anything meaningful for "DR". If I understand correctly, peeking at
the representation with unsigned char is allowed. I'm surprised.
[...]

A DR is a Defect Report, basically a bug report against the Standard.
You can see the C99 DRs at
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm>.

I think the particular DR being discussed here is #260.

I've never settled on what a bug really is, and the meaning seems to change
depending on context. There are bugs in the standard, bugs in compilers,
bugs in programs, bugs because programs work that shouldn't. I've never
read an essay on what the full taxonomy of a bug is.

Heathfield uses "bug" where I would say "fatal mistake," eg, something
leading to a sgefault. Finally, there are the cynics who claim that any
sufficiently-advanced feature is indistinguishable from a bug.
 

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

Similar Threads


Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top