This is the mail archive of the glibc-linux@ricardo.ecn.wfu.edu mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: malloc problem/question in 2.1.3


Kathy Bieltz wrote:

> Kaz,
>
> Kaz Kylheku wrote:
>
> > On Mon, 5 Jun 2000, Kathy Bieltz wrote:
> >
> > > Date: Mon, 05 Jun 2000 08:31:50 -0500
> > > From: Kathy Bieltz <kbieltz@hal-pc.org>
> > > Reply-To: glibc-linux@ricardo.ecn.wfu.edu
> > > To: glibc-linux@ricardo.ecn.wfu.edu
> > > Subject: Re: malloc problem/question in 2.1.3
> > >
> > > Mike,
> > >
> > > Do you do any XWindows programming???  One of the more
> > > common and hard to track down problems are SIGSEGV's
> > > caused by inadvertently freeing memory that was not previously
> > > allocated.

I have done X Windows programming, however not extensively.  Nonetheless, the
problem you describe should be avoidable with clean programming, albeit most or all
rules do have exceptions; just that this one is undocumented, afaik, and I've never
come across the need.

> >
> > This simply means that you have bungled your logic for initializing and
> > destroying subsystems and objects.  This could be the result of poor planning
> > at the design stage.
> >

Definitely can be and poor design is what I was initially getting at.  Seems like
some have grasped that point.

> Or you could be debugging legacy XWindow code developed by
> a programmer who has left for a project already overdue without
> the benefit of tools like Electric Fence.

Of course, there's a number of possible reasons why someone would create unusual
code.  What we're referring to isn't extremely unusual, however it is not common and
never appeared in any C code I've written or maintained.  Etc.

Nonetheless, sometimes patch work is necessary, to make up for flaws another created
or inherent in a certain implementations of ANSI C or other ANSI'd languages.


> >
> > > char* ptr = NULL ;
> > >
> > > if (ptr != NULL) {
> > >    free(ptr) ;
> > >    ptr = NULL ;
> > > }
> >
> > This is not necessary. Calling free on a null pointer is permitted by ANSI C.

ANSI is more or less unreliable, at least wrt C, historically.  Like someone else
said earlier (may have only been in private email - am not sure), ANSI doesn't
define how functions are to be implemented, not in detail anyway.  Two C functions
named x abiding by ANSI C and for two different platforms, say, are not necessarily
equal.  The inputs and outputs will or should be the same, however the functions can
be implemented differently, with one potentially being more correct.  ANSI doesn't
provide or define internal certainty.

> > Look it up in your library reference manual.  So you could just write:
>
> Not all the platforms the code I port to use ANSI C compilers.  We're
> trying to phase out support for those platforms so I might be able to
> take advantage of this in the future.

That's an issue, but separate.


> >     free(ptr);
> >     ptr = NULL;
> >
> > > This makes sure you don't inadvertently free memory not previously
> > > allocated.
>
> > The problem with doing this solely for the purpose of trying to prevent bugs is
> > that it may incapacitate the effectiveness of tools that are designed to find
> > the problem, such as ElectricFence. By turning undefined behavior (calling free
> > on an indeterminate pointer) into well-defined behavior (calling free on a null
> > pointer) you may mask the bug, making it harder to pinpoint when the invalid
> > second call to free took place. You will have to work backwards from the
> > failed use of the null pointer to deduce out how it got that way

That's a worthy or useful educational explanation for those who aren't familiar with
EF, a tool I only recently began to learn about.   Bugs should not be hidden.
Ideally, they should be eliminated, entirely.  Ideally, bugs shouldn't be
introduced, at all, however this is easier said than done, particularly when working
under pressing time constraints.

> > > It's quite common to define pointers and then use malloc to
> > > allocate at runtime only the memory needed to display an image.
> > > If it's a photo display program, many different sized images may
> > > be displayed in one program and the same pointer to the image
> > > data would be free'd and re-allocated for each new image selected.
> >
> > That's a special case; you have a short lived object, with a possible state of
> > ``not present'' which needs to be indicated by a null value of the pointer, or
> > some other thing; the null value is necessary to the logic.

I assumed as much, but just verified the output of malloc (and calloc) to be
certain.  If these functions fail, then they return NULL; therefore, reinit'ing a
ptr to null immediately after free was applied to the ptr does not make sense, even
if free is said to return no value.  Also, we normally init before using, instead of
after destroying.

The following could appear in code, using pseudo code for the illustration, because
this is not to teach syntax:

if ptr != null then
   free ptr
   ptr = null
endif
ptr = malloc( ... )

However, if we have a function with this kind of code in the while loop and the ptr
is only used within this while loop, then the following could apply:

sometype * ptr;
while ( some condition ) do
   ptr=malloc(...);
   if ptr == null then print can't get memory and exit;
   do your thing with the ptr;
   free ptr;
done

The return value of malloc should always be verified, for portability.  In VAX/VMS,
this is apparently unnecessary, at least according to C programs I've maintained on
VMS.  However, for the sake of portability, I don't care what platform I work on.

If the ptr is used after the loop terminates, then ptr=null would be added following
the done line, unless realloc was going to be used, instead of malloc.

Hence, for the above short lived object application, I'ld verify the code carefully,
to be certain.


> I guess I work with alot of special case code since my programs read in
> a lot of different kinds of data with a variable size.

Am not sure that this reason thoroughly or at all supports the necessity, as opposed
to improper design of logic being the necessitating factor.  However, without seeing
the code, it's a little too difficult to imagine that this kind of coding would be
necessary.

mike



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]