[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