[vox-tech] malloc() is ... old school?

Micah J. Cowan vox-tech@lists.lugod.org
Fri, 21 Mar 2003 12:53:34 -0800


On Fri, Mar 21, 2003 at 11:22:56AM -0800, Tim Riley wrote:
> 
> 
> "Micah J. Cowan" wrote:
> 
> > On Thu, Mar 20, 2003 at 04:52:15PM -0800, Tim Riley wrote:
> > >
> > >
> > > "Micah J. Cowan" wrote:
> > >
> > > > On Thu, Mar 20, 2003 at 10:15:43AM -0800, Tim Riley wrote:
> > > > >
> > <snip>
> > >
> > > The vulnerability with malloc() occurs when working with pointers.
> > > It's common to test if a pointer has been set
> > > by placing it inside an "if" statement before referencing it.
> > > If you always use calloc(), all of your pointers will be
> > > initialized with zero.
> >
> > All bits zero != NULL. This is a common misbelief, which happens to be
> > true on a number of platforms. But it is not guaranteed to be true,
> > and is not on several platforms, though I conced that they are not the
> > mainstream. See:
> >
> >   Sec. 5 of the C FAQ: ~http://www.eskimo.com/~scs/C-faq/s5.html
> >
> >   Any number of comp.lang.c posts:
> >     http://groups.google.com/groups?as_q=NULL%20calloc%28%29&as_ugroup=comp.lang.c
> >
> >   Especially this one by the author of the FreeBSD C Library (last paragraph):
> >     http://groups.google.com/groups?q=NULL+calloc()+group:comp.lang.c+author:Chris+author:Torek&selm=18764%40dog.ee.lbl.gov
> >
> >
> 
> "man calloc" on a Linux machine says bluntly:
>        calloc() allocates memory for an array of  nmemb  elements
>        of  size bytes each and returns a pointer to the allocated
>        memory.  The memory is set to zero.
> 
>        malloc() allocates size bytes and returns a pointer to the
>        allocated memory.  The memory is not cleared.

Yes. And?

What have I said that disagrees with this?

As I've already said, "zero" != NULL. Read my comment again.

> > > For the following example
> > > it's clear that a core dump might occur; however, if the program were
> > > 1000 lines long and the variables set in different locations, tracing
> > > could be a bear.
> > >
> > > typedef struct
> > > {
> > >     char *name;
> > >     char *address;
> > >     char *city;
> > >     char *state;
> > >     char *zip_code;
> > > } PERSON;
> > >
> > > int main( int argc, char **argv )
> > > {
> > >     PERSON *person = malloc( sizeof( PERSON ) );
> > >
> > >     person->name = "fred";
> >
> > A core dump could occur right here, with or without calloc(),
> > considering you didn't check malloc()'s return.
> 
> Allocation error checking was intentionally left out for simplicity.

Okay: but considering the message you were trying to send, it helps a
little to include a comment to this effect.

> > >     if ( person->name && person->zip_code )
> > >     {
> > >         printf( "For person = %s, got zip code = %s\n",
> > >                 person->name, person->zip_code );
> > >     }
> > > }
> > >
> > > If calloc() had been used, no one would have noticed the delay and no
> > > core would be dumped.
> >
> > Provided that one is using a system on which NULL happens to be
> > all-bits-zero.
> 
> What ANSI C implementation are you referring to here?

These: http://www.eskimo.com/~scs/C-faq/q5.17.html

Unsure whether these are all ISO C, but it really doesn't matter. The
fact that it is allowed by the ISO C standards ought to be enough for
a portability-minded programmer to avoid assuming that a calloc()'d
pointer will be NULL.

> 
> > Which we all are on this list, but can we guarantee
> > that the code you write won't be ported to such a system?
> >
> 
> Isn't this a Linux users group? What system are you referring to?

Yes; but is this thread only about ISO C implementations for Linux, or
is it about the ISO C language itself? If the former is our only
consideration, then I apologize for making an issue out of this: you
may employ whatever system-specific coding conventions you wish.

> Does it not have gcc? Is it open source so we can fix it?

"Fix it?" Why fix an ISO-conformant C implementation? On any systems
which have such a C implementation, the reason is most likely that the
system already has its own convention for how the null pointer should
be represented; "fixing" it would be ill-advised. In any case, as long
as you are coding properly, it should never be an issue: converting a
zero-value integer to a pointer will still yield the null pointer
value; and null pointers will always compare equal to the integer 0
regardless of how the null pointer is represented internally. These
are ISO requirements. What's not an ISO requirement is that something
like:

  memset(ptr_ptr, 0, sizeof *ptr_ptr);

or:

  ptr_ptr = calloc(1, sizeof *ptr_ptr);

leaves ptr_ptr[0] as a null pointer.


> 
> >
> > And I submit that without the core dump, the bug of having forgotten
> > to set *person's fields just got much, much harder to track down.
> >
> 
> Core dumps are useful for tracking down bugs.
> 

Exactly. So why use a coding style which would silently hide the bug
of having forgotten to properly set (*person)'s fields, possibly
wreaking havoc in much more sinister and subtle ways, instead of
consistently generating a loud core dump for the developer to realize,
"Oh! There must be a bug! Hey, look - I forgot to initialize this."?

My aim when I code is to write so that any mistakes I make, even very
little ones, will bring my program to a screeching halt during
development phase, so I can search and destroy it quickly. assert(),
Electric Fence, and redundant self-checks are great for this sort of
thing.

-Micah