Check for NULL before calling free()?

P

Poster Matt

First up I've found conflicting advise on the web about this.

I'm using gcc to compile some C Linux code I've written, having started writing
C code again for the first time in almost 15 years, I'm a bit rusty to say the
least.

Is it necessary, or even desirable in any way, to check whether a pointer points
to NULL before calling free()? In other words should free() only be called on
pointers that definitely do not == NULL? Is there any harm in calling free()
with a NULL pointer?

Thanks.
 
B

Ben Bacarisse

Poster Matt said:
First up I've found conflicting advise on the web about this.

I'm using gcc to compile some C Linux code I've written, having
started writing C code again for the first time in almost 15 years,
I'm a bit rusty to say the least.

Is it necessary, or even desirable in any way, to check whether a
pointer points to NULL before calling free()? In other words should
free() only be called on pointers that definitely do not == NULL? Is
there any harm in calling free() with a NULL pointer?

It is perfectly safe to call free(NULL). It's been safe since the
first time C was standardised (1989) so it is vanishingly unlikely
that you'll come across an archaic C library that does not permit it.

BTW, when you check if (p == NULL) you are not checking "whether a
pointer points to NULL" but whether a pointer *is* null. A null
pointer does not point anywhere.
 
T

Tom St Denis

It is perfectly safe to call free(NULL).  It's been safe since the
first time C was standardised (1989) so it is vanishingly unlikely
that you'll come across an archaic C library that does not permit it.

BTW, when you check if (p == NULL) you are not checking "whether a
pointer points to NULL" but whether a pointer *is* null.  A null
pointer does not point anywhere.

Strictly speaking a null pointer is defined as ((void*)0) which points
to the zero address. The only real reason that causes problems on
modern architectures is the offset is typically not mapped to a
segment [or section] and causes a page fault (usually the first 64KB)
when dereferenced. And the reason for that is some functions return
NULL on error and it's a good way to detect it.

But that's not always the case. In MS-DOS for instance, you could
dereference a long pointer of 0:0 (it's the interrupt vector table)
and it wouldn't cause any fault (mostly because in 16-bit mode by
default you cannot create a page fault, I say by default because you
can actually change segment limits in real mode ala unreal mode).

Tom
 
R

Richard Tobin

Tom St Denis said:
Strictly speaking a null pointer is defined as ((void*)0) which points
to the zero address.

This must be some use of the phrase "strictly speaking" with which
I was not previously acquainted!

In practice, the null pointer is generally implemented as an address
with all bits zero, and modern systems do indeed unmap the page
containing it. But that's just the obvious implementation, not the
definition. It could be implemented as the address 0x12345678, and
it might be useful to do this in a debugging implementation.

-- Richard
 
T

Tom St Denis

This must be some use of the phrase "strictly speaking" with which
I was not previously acquainted!

In practice, the null pointer is generally implemented as an address
with all bits zero, and modern systems do indeed unmap the page
containing it.  But that's just the obvious implementation, not the
definition.  It could be implemented as the address 0x12345678, and
it might be useful to do this in a debugging implementation.

I thought C99 defined it literally as

#define NULL ((void*)0)

Which would be the zero address to me. Where that *maps* to is a
different question.

That's like saying

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?

Tom
 
P

Poster Matt

I was just reading the wikipedia Malloc page. In the 'Memory Leaks' section:

http://en.wikipedia.org/wiki/Malloc#Memory_leaks

It says:

"When a call to malloc, calloc or realloc succeeds, the return value of the call
should eventually be passed to the free function. This releases the allocated
memory, allowing it to be reused to satisfy other memory allocation requests. If
this is not done, the allocated memory will not be released until the process
exits (and in some environments, not even then) — in other words, a memory leak
will occur. Typically, memory leaks are caused by losing track of pointers, for
example not using a temporary pointer for the return value of realloc, which may
lead to the original pointer being overwritten with a null pointer, for example:..."

Note that it says "the allocated memory will not be released until the process
exits (and in some environments, not even then)".

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

If not, under what circumstances would it not be?

Thanks.
 
N

Nick Keighley

no. The NULL macro is defined to be a null pointer constant that is
lexically represented as an expression that yields the value zero.
This may be cast to void*. How a null pointer constant is actually
represented in a running machien is up the implementer. And a few
implementers have chosen not to use the obvious all-bits-zero.

It does not need to point to the zero address and dereferencing a null
pointer gives Undefined Behaviour, byt definition not because of some
implementaion specific page mapping problem.

Read the FAQ. Especially section 5 "Null Pointers"
http://c-faq.com/null/index.html
 
N

Nick Keighley

I thought C99 defined it literally as

#define NULL ((void*)0)

dunno. C89 certainly didn't. C++ doesn't.

Which would be the zero address to me.

no, it isn't the zero address.
 Where that *maps* to is a different question.

"maps"? As in VM?

That's like saying

int *a, *b;

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

Assuming no overflow b > a right?  

or b might be invalid address that caused the program's behaviour to
be undefined. If the memory 'a' is pointing to is 1024 or more sizeof
(int) long then b will be well defined. And larger than 'a'. Even then
dereferencing b would be UB if b pointed one past the end of 'a''s
memory block

But is it possible that b maps to physically lower than a?

is this still VM?
 
N

Nick Keighley

I was just reading the wikipedia Malloc page. In the 'Memory Leaks' section:

http://en.wikipedia.org/wiki/Malloc#Memory_leaks

It says:

"When a call to malloc, calloc or realloc succeeds, the return value of the call
should eventually be passed to the free function. This releases the allocated
memory, allowing it to be reused to satisfy other memory allocation requests. If
this is not done, the allocated memory will not be released until the process
exits (and in some environments, not even then) — in other words, a memory leak
will occur. Typically, memory leaks are caused by losing track of pointers, for
example not using a temporary pointer for the return value of realloc, which may
lead to the original pointer being overwritten with a null pointer, for example:..."

Note that it says "the allocated memory will not be released until the process
exits (and in some environments, not even then)".

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

a modern OS should release the program's (process's) memory. Linux and
Windows do.
If not, under what circumstances would it not be?

you had a really poor OS or an old DOS system.

Maybe some of the embedded people can enlighten us if there are any OS
or runtime systems that don't clean after a bad exit (but then /their/
programs never terminate :) )
 
E

Eric Sosman

I thought C99 defined it literally as

#define NULL ((void*)0)

No; that's one of the possible definitions of a "null
pointer constant." Some others are 0, (!1), and __nil__ (on
an implementation where that makes sense).

There are at least two more layers of indirection between
what a "null pointer constant" looks like in source code and
what a "NULL-valued pointer variable" looks like in execution.
First, the fact that you've written some kind of a zero in the
source does not imply that what's stored has any resemblance
to a zero-valued integer: just as (float)1 need not have
exactly one one-bit, so (void*)0 need not have none. Second,
what's stored may depend on the type of the pointer variable
whose value compares equal to NULL: char* and int* values may
look different on word-addressed machines, and function pointers
are completely different from data pointers on some others.

Finally, a NULL-valued pointer variable does not point to
"the zero address." A NULL-valued pointer has three important
properties: (1) all NULL-valued pointers compare equal, (2) no
NULL-valued pointer compares equal to any pointer to an actual
data object or function, and (3) attempting to dereference a
NULL-valued pointer of any type yields undefined behavior. No
other properties (like "where it points" or "what it looks like")
are given. (Any particular implementation necessarily defines
the latter, but no implementation is actually required to define
the former.)
Which would be the zero address to me. Where that *maps* to is a
different question.

That's like saying

int *a, *b;

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

Assuming no overflow b> a right?

"Assuming no overflow" means "blah() returns a pointer to
an int followed by at least 1023 others." In that (trivial)
case, b>a. If blah() returns NULL or a pointer to fewer than
1024 ints, nothing can be said about a and b -- it may not even
be possible to compute b.
But is it possible that b maps to
physically lower than a?

Not sure what you mean by "physically lower." If you're
talking about a well-defined computation, we know b>a. If the
computation isn't well-defined, we know nothing about b. If
you're talking about a virtual-to-physical address translation
in an MMU, the effects are not visible to the C program and
the question can't be answered in C's terms. (In particular,
C cannot tell whether the physical addresses, if they exist,
are subject to any kind of ordering relation.)
 
B

Ben Bacarisse

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

#define NULL ((void*)0)

No, though that is one possible definition that meets C99's
requirements for NULL. C99 (and C89 for that matter) defines NULL as
a macro "which expands to an implementation-defined null pointer
constant" so it could conceivably be something "magic" like:

#define NULL __C_null_pointer_constant

or something as simple as 0.

That tells us about NULL, but it does not tell us what a null pointer
is in general. A null pointer is the result of converting a
null-pointer constant to some pointer type (6.3.2.3 p3). Thus 0 is a
legitimate null pointer constant, but (int *)0 is a null pointer (of
type int *) and is not, surprisingly, a null pointer constant. Also,
both (int *)0 and (double *)0 are null pointers but they can't be
compared one to the other. They will, however, both compare equal to
NULL.
Which would be the zero address to me. Where that *maps* to is a
different question.

I'd say that a null pointer does not map anywhere. Because
dereferencing a null pointer is undefined, an implementation is
permitted to do whatever it likes. I could, for example, simply
return what is found at address zero; or any at other address it
chooses; or it could also return random data unrelated to any address
-- i.e. there does not have to be any one place to which null pointers
map. All bets are off.

<snip>
 
P

Poster Matt

Nick said:
a modern OS should release the program's (process's) memory. Linux and
Windows do.


you had a really poor OS or an old DOS system.

Ok. Thanks for the clarification Nick.

I think it's been 15 years since I posted to this group (before today).

How nice to see that it's as active and helpful as ever. :)
 
K

Keith Thompson

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

#define NULL ((void*)0)

That's one legal definition. Another is 0. Another is
((void*)(0ULL). Another is ('/'/'/'-'/'/'/').
Which would be the zero address to me.

(Here we go again.)

C99 6.3.2.3p3:

An integer constant expression with the value 0, or such an
expression cast to type void *, is called a _null pointer
constant_. If a null pointer constant is converted to a
pointer type, the resulting pointer, called a _null pointer_,
is guaranteed to compare unequal to a pointer to any object
or function.

(This has not changed significantly since C90.)

Note that a "null pointer constant" is a source code construct;
a "null pointer" is a value that exists during execution of the
program.

The conversion may be non-trivial. An implementation can choose to
treat (void*)0x00000000 as a valid address, and (void*)0xdeadbeef
as a null pointer. Then converting a null pointer constant to void*
would yield a null pointer of type void*, which might have the same
representation as, say, the unsigned int value 0xdeadbeef.

If C had been designed slightly differently, there might be
a keyword, say "null" that represents (and is the only way to
represent) a null pointer constant. There would be no implication
that a null pointer has any particular representation. The semantics
of an if statement would be slightly expanded to say that, if the
expression is of pointer type, it's compared to null rather than
to 0.

In fact, C does pretty much the same thing, except that the syntax
of a null pointer constant is as described in C99 6.3.2.3p3 rather
than a simple keyword.

Oh, and the macro NULL expands to "an implementation-defined null
pointer constant". This can actually cause portability problems,
since NULL can be of type void* or of any integer type. So if you
want to pass NULL as a variadic function argument, you need to cast
it to a pointer type.

See also section 5 of the comp.lang.c FAQ, <http://www.c-faq.com/>.

<DIGRESSION>
A very strict reading of the standard implies that ((void*)0) is
not a null pointer constant, and therefore not a valid definition
for NULL. The problem is that C99 6.5.1p5 neglects to say that
a parenthesized null pointer constant is a null pointer constant.
This is clearly an unintentional oversight As far as I know all
C compilers accept ((void*)0) as a null pointer constant, and many
have "#define NULL ((void*)0)" in <stddef.h>.
</DIGRESSION>
 
E

Eric Sosman

[...] A NULL-valued pointer has three important
properties: (1) all NULL-valued pointers compare equal,[...]

After reading Ben Bacarisse's post, a correction: All
NULL-valued pointers compare equal to NULL or to any other
null pointer constant, but pointers of incompatible types
(NULL-valued or otherwise) cannot be compared to each other
at all and hence can't be said to "compare equal." Sorry
for the misteak.
 
E

Ersek, Laszlo

Note that it says "the allocated memory will not be released until the process
exits [...]"
Is this ever really the case in modern UNIX/Linux systems (or for that matter
any modern OS)?

Yes. On GNU/Linux:

http://www.gnu.org/s/libc/manual/html_node/Malloc-Tunable-Parameters.html

In my understanding:

- An allocation request (malloc()) with a size above a configurable
threshold (M_MMAP_THRESHOLD) is satisfied (if at all) with an mmap()
syscall. This creates a separate VMA for the process and is returned to
the OS when freed.

- Requests not above the limit are usually serviced within the single
(growable) "heap VMA" (if at all). This VMA is not free from
fragmentation ("fragmentation" being a user-space / libc concept). If
the top-most chunk is freed (via free()), the VMA can be resized (via
sbrk() and consequently probably mremap()) and memory (= address space
and possibly backing store) can be returned to the kernel, subject to
M_TRIM_THRESHOLD and M_TOP_PAD. If the top-most chunk is never free()'d,
then the heap VMA can never be shrunk.

Wrt. VMA's:

http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory

IIRC, OpenBSD switched sometime to a completely mmap()-backed
malloc()/free() implementation. Combined with randomized mmap(),
dereferencing stale pointers (= undefined behavior) leads immediately to
SIGSEGV (instead of corrupting other data in the heap VMA for a while,
then crashing in an unrelated location). The price might be higher
memory usage (each single allocation, no matter how small, allocates a
full page) and worse performance (each single allocation, no matter how
small, requires a system call, and the manipulation of the in-kernel VMA
container.) On the other hand, all free()'d regions should be
immediately returned to the system.

http://kerneltrap.org/node/5584

I guess one could imitate this behavior on GNU/Linux by setting
M_MMAP_THRESHOLD to 0.

-o-

This post of mine is most likely wildly inaccurate.

Cheers,
lacos
 
C

Christopher Bazley

a modern OS should release the program's (process's) memory. Linux and
Windows do.


you had a really poor OS or an old DOS system.

Maybe some of the embedded people can enlighten us if there are any OS
or runtime systems that don't clean after a bad exit (but then /their/
programs never terminate  :)  )

Under (ex-Acorn) RISC OS, runtime environments for kernel extension
modules written in C typically map the malloc, realloc, calloc and
free functions to a SWI which claims / resizes / frees blocks of
memory in a system-wide heap known as 'relocatable module area' (RMA).
This same heap also contains the code and workspace (i.e. external and
static variables) for modules. Any heap blocks not explicitly freed
upon finalisation of a module will be leaked.

Non-module tasks do not suffer from this problem because runtime
environments instead typically manage a heap within application
memory, which is automatically reclaimed by the OS when a task exits.

Anyway, my point is that it depends as much on the runtime environment
as the operating system. One could create a runtime environment for
RISC OS modules that kept track of RMA blocks allocated by malloc/
calloc/realloc and freed them automatically upon finalisation, or one
which creates a 'dynamic area' (DA) for each module instantiation and
manages a private heap within that (RMA is an example of a DA). The
latter solution would be prone to address space exhaustion because DAs
are not paged in and out of the memory map like application memory
blocks.
 
P

Poster Matt

I've another question, on a very similar subject, so am replying to my own post
about it rather than starting another thread.

The function in question uses strtok() to separate a string so I can get at the
part of the string I'm interested in.

Here's the code fragment, note that readBuffer is already full, if it does not
contain some chars then the following code will never be reached:

readBuffer will contain a string like: "Something=SomethingElse", I'm after the
"SomethingElse" bit.

-----------------------------------------------
char delimiter[] = "=";
char* split = NULL;

split = strtok(readBuffer, delimiter);

if (split == NULL)
{
free(readBuffer);
return NULL;
}

split = strtok(NULL, delimiter);

if ( (split == NULL) || (strlen(split) < 1) )
{
free(readBuffer);
return NULL;
}

char* tag = NULL;
int tagLen = strlen(split) + 1;
tag = (char*) malloc(tagLen);
strcpy(tag, split);

free(readBuffer);
return tag;
-----------------------------------------------

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? Does it get automatically freed when the function returns? It's
entirely possible that the function which contains the above code fragment could
be called several hundred times during the program's execution, though 70-80
times would be more typical.

Thanks again c.l.c.ers.
 
B

Ben Bacarisse

Poster Matt said:
I've another question, on a very similar subject, so am replying to my
own post about it rather than starting another thread.

Fresh on-topic threads are like gold-dust at the moment. Feel free to
start lots of them!
The function in question uses strtok() to separate a string so I can
get at the part of the string I'm interested in.

Here's the code fragment, note that readBuffer is already full, if it
does not contain some chars then the following code will never be
reached:

readBuffer will contain a string like: "Something=SomethingElse", I'm
after the "SomethingElse" bit.

-----------------------------------------------
char delimiter[] = "=";
char* split = NULL;

split = strtok(readBuffer, delimiter);

if (split == NULL)
{
free(readBuffer);
return NULL;
}

split = strtok(NULL, delimiter);

if ( (split == NULL) || (strlen(split) < 1) )

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.
{
free(readBuffer);
return NULL;
}

char* tag = NULL;
int tagLen = strlen(split) + 1;
tag = (char*) malloc(tagLen);

There's no need to cast the return from malloc but it *is* a good idea
to test the return.
strcpy(tag, split);

free(readBuffer);
return tag;
-----------------------------------------------

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? Does it get
automatically freed when the function returns?

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.

<snip>
 
S

Seebs

Is it necessary, or even desirable in any way, to check whether a pointer points
to NULL before calling free()? In other words should free() only be called on
pointers that definitely do not == NULL? Is there any harm in calling free()
with a NULL pointer?

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.

That said, if I have to check whether a pointer is null *anyway*, I tend to
put the free inside the check to save a call.

e.g.:
void
free_foo(foo *f) {
if (f) {
free(f->p1);
free(f->p2);
free(f);
}
}

Note that I don't check for p1 and p2, even though they're both presumably
capable of being NULL.

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

-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,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top