Check for NULL before calling free()?

S

Seebs

The code works fine. My question concerns using free() with the char* split. The
help page I read concerning the use of strtok() said specifically NOT to
"free(split);" and I'm not doing so. But what happens to the memory pointed to
by char* split?

It's part of the buffer. Nothing special has to happen to it.

You don't need to free a pointer which wasn't allocated. Basically:
char foo[] = "a=b";
char *split = foo + 2;

What happens to the memory pointed to by split? When foo is deallocated, all
of foo is deallocated, including the part split points to.

-s
 
B

Ben Pfaff

Seebs said:
You don't need to free a pointer which wasn't allocated.

This is true. But you would still be accurate if you said it in
a stronger way: You must not free a pointer which wasn't
allocated.
 
R

Richard Tobin

Tom St Denis said:
I thought C99 defined it literally as

#define NULL ((void*)0)

Others have explained that it doesn't have to be that.
Which would be the zero address to me.

Imagine a language just like C, except that instead of using "0' or
"(void *)0" or any of the other possibilities for the null pointer, it
uses a special keyword, "nil" perhaps. There would be no implication
of it having anything to do with zero. How it was represented
internally would be entirely up to the compiler.

The real C is just like that, except that you spell "nil" as "0" or
"(void *)0". The zeroness of it only appears in the source code. It
doesn't have to turn into a pointer in the same way that, for example,
(void *)0x10101010 does. In particular,

int x = 0;
if((void *)x == (void *)0)
printf("yes\n");
else
printf("no\n");

may print either result.
int *a, *b;

a = blah();
b = a + 1024;

Assuming no overflow b > a right? But is it possible that b maps to
physically lower than a?

Yes, there may be a non-trivial mapping from C's pointers to the
architecture's virtual addresses - though there usually isn't - and
there may be a non-trivial mapping from those virtual addresses to
physical addresses - which there usually is. There may also be a
non-trivial mapping when integers are converted to pointers by a cast,
which again there usually isn't.

But the point is that there may be a *completely different* mapping
for the special case of a null pointer constant; even if (void *)x in
the example above produces a pointer with all bits zero, that doesn't
have to be the same as what (void *)0 produces.

-- Richard
 
P

Poster Matt

Seebs said:
I currently feel that the distraction of another layer of indentation and
conditionals is not worth it, in general. I find it much easier to
read:
for (i = 0; i < N; ++i)
free(foo);
than
for (i = 0; i < N; ++i)
if (foo)
free(foo);


Me too... and there lies what prompted my question in the first place!!

Cheers,

Matt
 
P

Poster Matt

Ben said:
I am pretty sure that strlen(split) < 1 is impossible. It relies on
some reasoning, so you might want to leave this in, but it would make
me do a double take and ponder the possibility.

I wasn't sure if possible or not, suspecting not. Being of a cautious nature I
added it under the supposition that it couldn't do any harm and just in case.

There's no need to cast the return from malloc but it *is* a good idea
to test the return.

Old habits die hard (you need the cast for C++). I removed the test of
malloc()'s return value from the code posted - less clutter.

Yes. strtok does not allocate any memory. It return pointers into
the buffer so freeing the buffer is enough. Of course, you copy the
string into a malloced area and that needs to be freed at some time,
but that is not what you were talking about.

Ok that's good news. I did the right thing without realizing exactly why.
Copying the section of readBuffer that I need into a newly allocated area of
memory, which is returned, and then freeing readBuffer. And yes the newly
allocated bit does get freed later on by the calling function after it's used it.

Thanks again Ben.
 
K

Keith Thompson

Yes, there may be a non-trivial mapping from C's pointers to the
architecture's virtual addresses - though there usually isn't - and
there may be a non-trivial mapping from those virtual addresses to
physical addresses - which there usually is. There may also be a
non-trivial mapping when integers are converted to pointers by a cast,
which again there usually isn't.

But the point is that there may be a *completely different* mapping
for the special case of a null pointer constant; even if (void *)x in
the example above produces a pointer with all bits zero, that doesn't
have to be the same as what (void *)0 produces.

Yes.

Another possibility is that all integer-to-pointer conversions might
use the *same* non-trivial mapping. For example, converting an
integer to a pointer of the same size might always invert all the
bits. Then (void*)0 and { int x = 0; (void*)x; } would both yield a
null pointer whose representation happens to be 0xFFFFFFFF.

Given:

int nonconstant_zero = 0;
void *null_pointer = (void*)0; /* yes, the cast is superfluous */
void *maybe_null_pointer = (void*)nonconstant_zero;

The value of null_pointer is guaranteed to be a null pointer.
The value of maybe_null_pointer may or may not be a null pointer.
null_pointer and maybe_null_pointer may or may not be equal.

As for their representations, null_pointer and maybe_null_pointer may
or may not be all-bits-zero; all 4 combinations are possible.

The standard does suggest in a footnote that conversions between
pointers and integers "are intended to be consistent with the
addressing structure of the execution environment"; inverting
all the bits is unlikely in practice, but there are other,
more realistic, possibilities.

(On the vast majority of current systems, both null_pointer and
maybe_null_pointer will contain null pointer values, and both will
have an all-bits-zero representation.)
 
C

Christopher Bazley

I currently feel that the distraction of another layer of indentation and
conditionals is not worth it, in general.  I find it much easier to
read:
        for (i = 0; i < N; ++i)
                free(foo);
than
        for (i = 0; i < N; ++i)
                if (foo)
                        free(foo);


I don't think that is such a good example as your first, because there
might be a significant time saving in not making a function call every
iteration of a loop.

As for the extra level of indentation, you can easily hide it in a
macro:

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

Not that I would advocate such a thing, since learning that function
macros "...cause more problems than they solve." (Kernighan and
Pike). ;-)
 
B

Bee Bradford

Tough call.  As of C89 and later (and thus pretty much all modern systems),
it's not required -- free(NULL) is harmless.

Some people like to do it as part of a general habit.  I tend not to.

I'm not too hung up on it, but I guess it sticks in my craw just a bit
that this goes against the so-called spirit of C. I just wonder why
this particular check is handled automatically, while all other
runtime error checking that I can think of is left up to the
programmer to implement.
 
S

Seebs

I'm not too hung up on it, but I guess it sticks in my craw just a bit
that this goes against the so-called spirit of C. I just wonder why
this particular check is handled automatically, while all other
runtime error checking that I can think of is left up to the
programmer to implement.

Interesting question!

Here's my thought: When I ask the library to strcpy, printf, or otherwise
USE a null pointer, I am implicitly referring to the thing-pointed-to. Unlike
these, "free()" really doesn't implicitly refer to the thing pointed to, only
to the pointer. (In practice, that may well imply referring to, say, space
just before the thing pointed to... But that's an internal detail.)

So there's a conceptual difference there. free() is only talking about the
pointer, not using it. It is easy to specify what to do for free(NULL) --
obviously, you don't want to do anything, because there's already no allocated
object there, and it is guaranteed trivial to determine this to be the case.

Contrast with:

free(invalid_ptr);
There is no obvious cost-effective way for the implementation to
determine that you've tried to free an invalid pointer, in the general
case, so it's not clear that it's reasonable to expect this to work.
strcpy(buffer, NULL);
What should this do? It can't just copy "until it reaches the \0",
nor can we guess whether you want this to copy zero bytes, or just
silently append a '\0', or what.
sprintf("%s", NULL);
Again, what should this do? Do you want no output? Something like
the string "(null)"? "<nil>"? The contents of memory location zero
up through the first '\0'?

But free(NULL) is both unambiguous and cheap to detect.

Similarly, you're probably more likely to encounter a variety of cases where
a pointer is either-null-or-allocated.

Finally, last but not least:

void *v;
v = malloc(N);
free(v);

This should work, because you should be able to free something that was just
returned by malloc. :)

-s
 
E

Eric Sosman

I've another question, on a very similar subject, so am replying to my
own post about it rather than starting another thread.
[...]
readBuffer will contain a string like: "Something=SomethingElse", I'm
after the "SomethingElse" bit.

Others have answered your principal question, about what
free() does to a pointer into the middle of a freed memory
area. I'd just like to point out that strtok() may not be the
best tool for the larger job, because it will do possibly
unwelcome things with "Something==SomethingElse" or with
"Something=1+1=2" and so on. You might want to consider using
strchr() to locate the '=', and perhaps to check that the
remainder contains no further '=':

split = strchr(readBuffer, '=');
if (split == NULL) {
handle_missing_equals();
}
else {
++split; /* first char after '=' */
if (*split == '\0') {
handle_empty_tail();
}
else if (strchr(ptr, '=') != NULL) {
handle_superfluous_equals();
}
else {
handle_valid_tail_starting_at(split);
}
}
 
R

Richard Tobin

Tough call. As of C89 and later (and thus pretty much all modern systems),
it's not required -- free(NULL) is harmless.

Some people like to do it as part of a general habit. I tend not to.
[/QUOTE]
I'm not too hung up on it, but I guess it sticks in my craw just a bit
that this goes against the so-called spirit of C. I just wonder why
this particular check is handled automatically, while all other
runtime error checking that I can think of is left up to the
programmer to implement.

But it's not error checking. The space of memory blocks covered by the
malloc() family includes the empty block whose address may be null.
If you're building an array incrementally, you can initialise it to
null and then pass it to realloc() without having to special case it.
(Or you can initialise it to the result of malloc(0), which may be
null.) Having to handle free()ing an empty block as a special case
would be pointless.

-- Richard
 
K

Kaz Kylheku

[... why free(NULL) is all right ...]
I'm not too hung up on it, but I guess it sticks in my craw just a bit
that this goes against the so-called spirit of C. I just wonder why
this particular check is handled automatically, while all other
runtime error checking that I can think of is left up to the
programmer to implement.

At a guess (I wasn't part of the debate), it's so that
*any* value returned by malloc(), calloc(), or realloc() is
fair game for free().

But null works even if it wasn't previously returned by any of
these functions, and you can free it as many times as you want.
A pleasant "uniformity" property.

It's the ``Null Object Design Pattern'': extend functions or methods
such that they handle a special null value gracefully instead of failing.
 
N

Nobody

Note that it says "the allocated memory will not be released until the
process exits [...]"

Note: you snipped the relevant part and left the irrelevant part.

Let's try a more complete and accurate quote:
Note that it says "the allocated memory will not be released until the
process exits (and in some environments, not even then)".

And did exactly the same thing again here.

Again, the complete quote:
Is this ever really the case in modern UNIX/Linux systems (or for that
matter any modern OS)? Surely in modern OS's when a process ends, all
memory used by that process is freed?!

He's not asking about the "until the process exits" case, he's asking
about the "and in some environments, not even then" case.
This post of mine is most likely wildly inaccurate.

It's accurate, but entirely irrelevant to the question which was actually
being asked, namely whether there are OSes where memory leaks persist
beyond the lifetime of the process.

Arguably, OSes where memory allocated by malloc() remains allocated after
exit() don't actually have "processes" in the normal sense of the word.
They just run programs like plug-ins or overlays, in a single global
environment, so exit() is little more than a longjmp() out to the main
program.

Generally, real multi-tasking, multi-user OSes (Unix, VMS, Windows NT)
have real processes whose resources are reclaimed upon termination.
Single-tasking OSes (some of which may have primitive multi-tasking
abilities) (DOS, RISC-OS, probably most 8/16-bit microcomputer operating
systems) are less likely to provide clean-up.
 
F

frank

Nobody said:
http://en.wikipedia.org/wiki/Malloc#Memory_leaks
Note that it says "the allocated memory will not be released until the
process exits [...]"

Note: you snipped the relevant part and left the irrelevant part.

Let's try a more complete and accurate quote:
Note that it says "the allocated memory will not be released until the
process exits (and in some environments, not even then)".

And did exactly the same thing again here.

Again, the complete quote:
Is this ever really the case in modern UNIX/Linux systems (or for that
matter any modern OS)? Surely in modern OS's when a process ends, all
memory used by that process is freed?!

He's not asking about the "until the process exits" case, he's asking
about the "and in some environments, not even then" case.
This post of mine is most likely wildly inaccurate.

It's accurate, but entirely irrelevant to the question which was actually
being asked, namely whether there are OSes where memory leaks persist
beyond the lifetime of the process.

Arguably, OSes where memory allocated by malloc() remains allocated after
exit() don't actually have "processes" in the normal sense of the word.
They just run programs like plug-ins or overlays, in a single global
environment, so exit() is little more than a longjmp() out to the main
program.

Generally, real multi-tasking, multi-user OSes (Unix, VMS, Windows NT)
have real processes whose resources are reclaimed upon termination.
Single-tasking OSes (some of which may have primitive multi-tasking
abilities) (DOS, RISC-OS, probably most 8/16-bit microcomputer operating
systems) are less likely to provide clean-up.

I think Ersek and you are talking past each other a bit. I suspect you
don't have the same mother tongue.

I grew up on windows so became weaned on OS's killing applications or
letting them run roughshod.

It's always good form to free memory, yet one person's memory leak is
another's application. When one creates constructor, well then there
also "needs to be" a destructor.

Just for kicks and giggles, I'm gonna see how much memory I can malloc.
 
B

Barry Schwarz

Strictly speaking a null pointer is defined as ((void*)0) which points
to the zero address. The only real reason that causes problems on

Strictly speaking, ((void*)0) is a null pointer constant. It only
becomes a null pointer after it is converted to pointer type.
[6.3.2.3-3]
 
B

Barry Schwarz

I'm going to pretend I haven't seen the excellent replies you've already
gotten and respond this way:

free(NULL) is guaranteed to be a NOP. It does not dereference the null
value. No harm no foul.

Freeing a non-null pointer value which was not returned from malloc() et al
causes Undefined Behavior. Freeing a valid value a second time is Undefined
Behavior. This is a Bad Thing (tm) and may set a fire somewhere.

It is not possible to free a valid value a second time. By
definition, when the memory pointed to by the value is freed the first
time, the value becomes indeterminate and you are not allowed to
evaluate it (such as passing it to free).
 
P

Phil Carmody

Seebs said:
Interesting question!

Here's my thought: When I ask the library to strcpy, printf, or otherwise
USE a null pointer, I am implicitly referring to the thing-pointed-to.

Disagree for %p. %p's less about the thing pointed to than free() imho,
as I'm tainted by knowing exactly what goes on behind a dozen different
implementations of free(). Unless rendering as %p isn't 'USE' of the
pointer, in which place you're probably being tautologious.

Phil
 
P

Phil Carmody

Kaz Kylheku said:
[... why free(NULL) is all right ...]
I'm not too hung up on it, but I guess it sticks in my craw just a bit
that this goes against the so-called spirit of C. I just wonder why
this particular check is handled automatically, while all other
runtime error checking that I can think of is left up to the
programmer to implement.

At a guess (I wasn't part of the debate), it's so that
*any* value returned by malloc(), calloc(), or realloc() is
fair game for free().

But null works even if it wasn't previously returned by any of
these functions, and you can free it as many times as you want.
A pleasant "uniformity" property.

It's the ``Null Object Design Pattern'': extend functions or methods
such that they handle a special null value gracefully instead of failing.

Braindead. If functions need modification to cope with a particular
type of object, then they violate the LSP. It's the null object
that should be created in such a way that it can be worked on by
those functions or methods gracefully in order to preserve the LSP.

Phil
 
P

Phil Carmody

Barry Schwarz said:
It is not possible to free a valid value a second time. By
definition, when the memory pointed to by the value is freed the first
time, the value becomes indeterminate and you are not allowed to
evaluate it (such as passing it to free).

Repeating for emphasis - you can't even check to see if the
previously-possibly-null value was indeed null or not.

Phil
 
S

Seebs

Disagree for %p. %p's less about the thing pointed to than free() imho,
as I'm tainted by knowing exactly what goes on behind a dozen different
implementations of free(). Unless rendering as %p isn't 'USE' of the
pointer, in which place you're probably being tautologious.

True. And %p of NULL is well-defined, but %s isn't.

-s
 

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,792
Messages
2,569,639
Members
45,353
Latest member
RogerDoger

Latest Threads

Top