what can cause free to segfault

  • Thread starter Ramprasad A Padmanabhan
  • Start date
R

Ramprasad A Padmanabhan

I am sorry for asking such a vague question.
I am having a program where I am allocating a char* variable some memory
and in the end of the loop freeing it. Funnily enough free hangs only
when a particular string is passed. A string longer , shorter or a
different string *does not* hang. This is totally repeatable.

This code is a part of a Sendmail/milter plugin , and I am not able to
replicate such a situtation to a stand alone program.

So are there any rules before I free() a malloc-ed char*
I am making sure I am not freeing a NULL variable
is there anything else

Thanks
Ram
 
C

Christopher Benson-Manica

Ramprasad A Padmanabhan said:
So are there any rules before I free() a malloc-ed char*
I am making sure I am not freeing a NULL variable
is there anything else

free( NULL ); is perfectly legal. Free will choke if you attempt to free
something you've already freed or something you did not malloc(). If you post
the relevant snippets of code, someone here can probably help you idenitify
the problem.
 
I

Irrwahn Grausewitz

Ramprasad A Padmanabhan said:
I am sorry for asking such a vague question.
I am having a program where I am allocating a char* variable some memory
and in the end of the loop freeing it. Funnily enough free hangs only
when a particular string is passed. A string longer , shorter or a
different string *does not* hang. This is totally repeatable.

This code is a part of a Sendmail/milter plugin , and I am not able to
replicate such a situtation to a stand alone program.

Maybe there is something wrong with another *alloc/free couple, or some
code is operating out of bounds, corrupting some information vital for
the memory allocator to work correctly.
So are there any rules before I free() a malloc-ed char*

Make sure you didn't already free it. A Good Idea[tm] is to set the
pointer to NULL after calling free().
I am making sure I am not freeing a NULL variable

Which would be a valid, free(NULL) is defined to be a non-action.

Regards
 
E

Ed Morton

Irrwahn Grausewitz wrote:

Make sure you didn't already free it. A Good Idea[tm] is to set the
pointer to NULL after calling free().

According to FAQ (http://www.eskimo.com/~scs/C-faq/q7.21.html:

"A pointer value which has been freed is, strictly speaking, invalid,
and any use of it, even if is not dereferenced can theoretically lead to
trouble, though as a quality of implementation issue, most
implementations will probably not go out of their way to generate
exceptions for innocuous uses of invalid pointers."

that introduces implementation-defined behavior so it may not work for
the OP.

For the regulars:

1) is this really a problem?
2) if so, would it be safe to write this code instead:

p = malloc(...);
tmp = p;
p = NULL;
free(tmp);

3) if not, why not?

Regards,

Ed.
 
S

Sheldon Simms

Irrwahn Grausewitz wrote:

Make sure you didn't already free it. A Good Idea[tm] is to set the
pointer to NULL after calling free().

According to FAQ (http://www.eskimo.com/~scs/C-faq/q7.21.html:

"A pointer value which has been freed is, strictly speaking, invalid,
and any use of it, even if is not dereferenced can theoretically lead to
trouble, though as a quality of implementation issue, most
implementations will probably not go out of their way to generate
exceptions for innocuous uses of invalid pointers."

that introduces implementation-defined behavior so it may not work for
the OP.

For the regulars:

1) is this really a problem?

Are you asking if using an already freed pointer is a problem?
If so, yes.
2) if so, would it be safe to write this code instead:

p = malloc(...);
tmp = p;
p = NULL;
free(tmp);

There's no problem here because you aren't using a pointer value
after it has been freed. after the second line, p and tmp both
contain the same pointer value. After the third line p is a null
pointer, but tmp still contains the pointer value that was originally
returned by malloc(). Freeing a pointer value returned by malloc(),
as in line 4, is ok.

-Sheldon
 
J

Jeremy Yallop

Ed said:
Irrwahn Grausewitz wrote:

Make sure you didn't already free it. A Good Idea[tm] is to set the
pointer to NULL after calling free().

According to FAQ (http://www.eskimo.com/~scs/C-faq/q7.21.html:

"A pointer value which has been freed is, strictly speaking, invalid,
and any use of it, even if is not dereferenced can theoretically lead to
trouble, though as a quality of implementation issue, most
implementations will probably not go out of their way to generate
exceptions for innocuous uses of invalid pointers."

that introduces implementation-defined behavior so it may not work for
the OP.

It's not clear to me whether by "that" you mean assigning to a pointer
whose value has been passed to free() or using the value of such a
pointer. The first is fine, the second has undefined behaviour.
Using the value of the pointer will "work" in practice in many (but
not all) implementations, but dereferencing the pointer is likely to
produce unexpected results.

Setting pointers to null after calling free() may help in some cases,
but it obviously doesn't affect other pointers to the same region. In
your example:
p = malloc(...);
tmp = p;
p = NULL;
free(tmp);

it's safe to use `p' after this code has executed, but any use of the
value of `tmp' has undefined behaviour.

Jeremy.
 
E

Ed Morton

Ed said:
Irrwahn Grausewitz wrote:

Make sure you didn't already free it. A Good Idea[tm] is to set the
pointer to NULL after calling free().

According to FAQ (http://www.eskimo.com/~scs/C-faq/q7.21.html:

"A pointer value which has been freed is, strictly speaking, invalid,
and any use of it, even if is not dereferenced can theoretically lead to
trouble, though as a quality of implementation issue, most
implementations will probably not go out of their way to generate
exceptions for innocuous uses of invalid pointers."

that introduces implementation-defined behavior so it may not work for
the OP.


It's not clear to me whether by "that" you mean assigning to a pointer
whose value has been passed to free() or using the value of such a
pointer.

Sorry it wasn't clear. My question is: given that the FAQ says that ANY use of a
pointer after free() can lead to trouble, is it true that assigning NULL to a
pointer after free() (and presumably testing it for NULL or passing it to free()
again later, otherwise why bother setting it to NULL) can lead to trouble? If
not, what is that statement in the FAQ supposed to mean since it clearly says
"even if it is not dereferenced..."?

Ed.
 
J

Jeremy Yallop

Ed said:
Ed said:
Irrwahn Grausewitz wrote:

<snip>

Make sure you didn't already free it. A Good Idea[tm] is to set the
pointer to NULL after calling free().

According to FAQ (http://www.eskimo.com/~scs/C-faq/q7.21.html:

"A pointer value which has been freed is, strictly speaking, invalid,
and any use of it, even if is not dereferenced can theoretically lead to
trouble, though as a quality of implementation issue, most
implementations will probably not go out of their way to generate
exceptions for innocuous uses of invalid pointers."

that introduces implementation-defined behavior so it may not work for
the OP.


It's not clear to me whether by "that" you mean assigning to a pointer
whose value has been passed to free() or using the value of such a
pointer.

Sorry it wasn't clear. My question is: given that the FAQ says that ANY use of a
pointer after free() can lead to trouble, is it true that assigning NULL to a
pointer after free() (and presumably testing it for NULL or passing it to free()
again later, otherwise why bother setting it to NULL) can lead to trouble?

No. The FAQ says "pointer value". Assigning to a pointer doesn't use
its value. Regarding your parenthetical remark, comparing a pointer
to NULL /does/ use its value and comparing a free()d value to NULL has
undefined behaviour.

One reason that some people set pointers to null after calling free()
is to ensure that invalid values can never be used (by making every
pointer point to valid memory or be null).

Jeremy.
 
S

Sheldon Simms

Ed said:
Irrwahn Grausewitz wrote:

<snip>

Make sure you didn't already free it. A Good Idea[tm] is to set the
pointer to NULL after calling free().

According to FAQ (http://www.eskimo.com/~scs/C-faq/q7.21.html:

"A pointer value which has been freed is, strictly speaking, invalid,
and any use of it, even if is not dereferenced can theoretically lead to
trouble, though as a quality of implementation issue, most
implementations will probably not go out of their way to generate
exceptions for innocuous uses of invalid pointers."

that introduces implementation-defined behavior so it may not work for
the OP.


It's not clear to me whether by "that" you mean assigning to a pointer
whose value has been passed to free() or using the value of such a
pointer.

Sorry it wasn't clear. My question is: given that the FAQ says that ANY use of a
pointer after free() can lead to trouble, is it true that assigning NULL to a
pointer after free() (and presumably testing it for NULL or passing it to free()
again later, otherwise why bother setting it to NULL) can lead to trouble? If
not, what is that statement in the FAQ supposed to mean since it clearly says
"even if it is not dereferenced..."?

The FAQ doesn't say that any use of a pointer _variable_ after free() can
lead to trouble. It says that any use of a pointer _value_ after free()
can lead to trouble.

An example of a non-dereferencing use of a freed pointer value would be:

char * p;
p = malloc(16);
...
free(p);
printf("p was %p\n", p);
 
C

Christopher Benson-Manica

Jeremy Yallop said:
One reason that some people set pointers to null after calling free()
is to ensure that invalid values can never be used (by making every
pointer point to valid memory or be null).

Does that, then, suggest a macro wrapper for free() such as

#define FREE( ptr ) free(ptr); ptr=NULL;

? If not, why not?
 
J

Jeremy Yallop

Christopher said:
Does that, then, suggest a macro wrapper for free() such as

#define FREE( ptr ) free(ptr); ptr=NULL;

? If not, why not?

This sort of thing is proposed fairly frequently. There are at least
the following issues to consider:

* FREE() doesn't behave sensibly as the body of an `if' statement.
See FAQ 10.4.

* FREE() evaluates ptr more than once, which is best avoided, if
possible.

* free() takes a value, not an object, so not all arguments to
free() are valid as arguments to FREE().

* FREE() does not (and cannot) do anything about other pointers to
the same region.

The last is the most significant, in my opinion.

Jeremy.
 
I

Irrwahn Grausewitz

Ed Morton said:
Irrwahn Grausewitz wrote:

Make sure you didn't already free it. A Good Idea[tm] is to set the
pointer to NULL after calling free().

According to FAQ (http://www.eskimo.com/~scs/C-faq/q7.21.html:

"A pointer value which has been freed is, strictly speaking, invalid,
and any use of it, even if is not dereferenced can theoretically lead to
trouble, though as a quality of implementation issue, most
implementations will probably not go out of their way to generate
exceptions for innocuous uses of invalid pointers."

that introduces implementation-defined behavior so it may not work for
the OP.

Assigning NULL to a pointer variable is not the same as using a
(invalid) pointer value.

#include <stdlib.h>
int main( void )
{
char *p = malloc( 42 );
free( p );
p = NULL;
return 0;
}

is valid code. And if it were not, any assignment of a valid value to
a before uninitialized pointer variable would invoke UB.

Regards
 
E

Eric Sosman

Sheldon said:
The FAQ doesn't say that any use of a pointer _variable_ after free() can
lead to trouble. It says that any use of a pointer _value_ after free()
can lead to trouble.

An example of a non-dereferencing use of a freed pointer value would be:

char * p;
p = malloc(16);
...
free(p);
printf("p was %p\n", p);

Undefined behavior, for two reasons:

- Using the value of `p' after the memory it formerly
referred to has been freed. (The Standard gives no
special dispensation to "non-dereferencing" uses;
*any* use of the stale value is bogus.)

- Passing a `char*' to "%p", which requires a `void*'.
(Yes, we know they have the same representation.
But that's not enough! For example, a sufficiently
perverse implementation might pass `char*' pointers
in the special "string registers," and pass other
pointer values by some other means.)
 
E

Ed Morton

Rats, I shoulda noticed that. So, it's saying that after free(p):

if (p == NULL)

or anything else other than an assignment is bad, but:

p = NULL;

is fine and then a subsequent:

if (p == NULL)

or anything else other than a dereference would also be fine.

Yeah, I get it now...
Undefined behavior, for two reasons:

- Using the value of `p' after the memory it formerly
referred to has been freed. (The Standard gives no
special dispensation to "non-dereferencing" uses;
*any* use of the stale value is bogus.)


Right - that's what he was demonstrating for those of us feeling a little
cognitively-challenged at the moment 8-(.

Thanks to all who replied.

Ed.
 
N

nrk

Ramprasad said:
I am sorry for asking such a vague question.
I am having a program where I am allocating a char* variable some memory
and in the end of the loop freeing it. Funnily enough free hangs only
when a particular string is passed. A string longer , shorter or a
different string *does not* hang. This is totally repeatable.

This code is a part of a Sendmail/milter plugin , and I am not able to
replicate such a situtation to a stand alone program.

So are there any rules before I free() a malloc-ed char*
I am making sure I am not freeing a NULL variable
is there anything else

The important rules are to pass only those pointers to free that were
obtained through *alloc functions, and not use them in any manner or form
after they've been freed once (except for assigning them new valid values
such as NULL or a return from *alloc). Passing NULL to free() is useless
and harmless.

<OT>
Heap corruption is notoriously difficult to debug. It is quite possible
that your heap is getting corrupted long before the particular piece of
code you're looking at is reached, and the corruption simply manifests
itself at this point. Some tools that may be of help (assuming you are on
a platform where they can be used) are checked memory allocators (typically
you link in a different library) such as electric fence, the simple
MALLOC_CHECK_ environment variable used by gcc, that makes it slightly more
tolerant of dynamic memory errors, valgrind that may or may not be a good
idea depending on the time you have in hand :) Additionally, if you
prefer to do it the old-fashioned way, try commenting out chunks of code,
till you end up with the smallest piece that reproduces the problem...
might help!! [of course, a clc pedant will rightly point out that all this
advice is BS as you might be working on a platform where there is no heap,
no stack, but instead theres a couple of lethargic hamsters that may or may
not be alive :)]
</OT>

-nrk.
 
M

Malcolm

Ramprasad A Padmanabhan said:
So are there any rules before I free() a malloc-ed char*
Technically, any undefined behaviour anywhere in the program could cause a
free() to fail.
In practise, the most likely explanation is that the pointer was already
freed, or wasn't returned by malloc(), or you altered its value, for
instance by incrementing it.
Another possibility is damage to the block, if you write past the end. You
need to find out where the illegal action is, and remove it.
 
S

Sheldon Simms

Undefined behavior, for two reasons:

- Using the value of `p' after the memory it formerly
referred to has been freed. (The Standard gives no
special dispensation to "non-dereferencing" uses;
*any* use of the stale value is bogus.)

This was the whole point of the FAQ information as quoted earlier
in the thread:

A pointer value which has been freed is, strictly speaking, invalid,
and any use of it, even if is not dereferenced can theoretically lead to
trouble,

The OP originally seemed to think that in

free(p)
p = NULL;

the second line was a non-dereferencing use of a pointer value. I
pointed out that it was not, and gave an example of a non-dereferencing
use of a pointer value.

The fact that such a use leads to undefined behavior was known right from
the beginning, since the whole discussion hinged on the FAQ information
in the first place, so your comment is not particularly useful or
informative.
- Passing a `char*' to "%p", which requires a `void*'.

This is a correction worth making. Thanks.

-Sheldon
 
P

Peter Pichler

Malcolm said:
Another possibility is damage to the block, if you write past the end. You
need to find out where the illegal action is, and remove it.

Or *before* the block (e.g. past something else, seemingly completely
unrelated), probably even more likely and definitely more difficult to track
down. Believe, been there, done that :)
 
E

Ed Morton

Sheldon Simms wrote:
The OP originally seemed to think that in

free(p)
p = NULL;

the second line was a non-dereferencing use of a pointer value.

No, I thought the FAQ was saying you coudln't reference a pointer
variable after a free. I just mis-read "pointer value" as "pointer
variable".
I
pointed out that it was not, and gave an example of a non-dereferencing
use of a pointer value.

Right. Thanks again.

Ed.
 
S

Sheldon Simms

Sheldon Simms wrote:


No, I thought the FAQ was saying you coudln't reference a pointer
variable after a free. I just mis-read "pointer value" as "pointer
variable".

Ok. I stand corrected.
 

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
474,093
Messages
2,570,613
Members
47,230
Latest member
RenaldoDut

Latest Threads

Top