Re: Memory leaks found by DMALLOC?
"raphael.huck" <[email protected]> Mon, 27 Oct 2008 17:24:56 -0000
| Newsgroups | gmane.text.clearsilver.general |
|---|---|
| Message-ID | <[email protected]> |
I've found the problem a long time ago, and forgot to post it.
I just stumbled on my old message, so I figured I'd post a followup :)
In fact the problem comes from cgiwrap_writef in cgi/cgiwrap.c:
NEOERR *cgiwrap_writef (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
cgiwrap_writevf (fmt, ap);
va_end (ap);
return STATUS_OK;
}
cgiwrap_writevf returns a NEOERR * which isn't checked in
cgiwrap_writef. If cgiwrap_writevf returns STATUS_OK, everything is
fine, if not, the allocated structure is never freed. That is the
memory leak I was talking about in my previous mail.
If we have a look at the code of cgiwrap_writevf, we can see:
r = GlobalWrapper.writef_cb (GlobalWrapper.data, fmt, ap);
if (r)
return nerr_raise_errno (NERR_IO, "writef_cb returned %d", r);
Thus, if the writef callback you have given to cgiwrap_init_emu
doesn't return 0, an error structure will be allocated and returned,
but never handled.
The quick solution is to simply have the writef callback always return
0: cgiwrap_writevf will then never allocate an error structure, so no
memory leak.
So instead of doing this (which triggers the memory leak):
int writef_cb(void *ptr, const char *format, va_list ap)
{
UNUSED(ptr);
return FCGI_vprintf(format, ap);
}
do this:
int writef_cb(void *ptr, const char *format, va_list ap)
{
UNUSED(ptr);
FCGI_vprintf(format, ap);
return 0;
}
The cleaner solution would be to modify cgiwrap_writef in order to
handle the error returned by cgiwrap_writevf.
But then each call to cgiwrap_writef should have to check the return
value, and deal with the potential error structure, or there would be
even more memory leaks.
In cgi/cgi.c there are several calls to cgiwrap_writef which don't
check the return value...
So I don't know if the clean solution is a good idea.
What do you think Brandon?
Thanks in advance for your advice.
--Raphaël
>
> > I'll try to find more information about the leaked memory.
> >
> > I forgot to mention that when I comment out the following lines:
> >
> > err = cgi_display(cgi, "test.cst");
> > nerr_ignore(&err);
> >
> > there are no longer memory leaks, so it seems to come from
cgi_display.
>
> I've found more information.
>
> I'm using the following wrappers for FastCGI:
>
> /* FCGI_fread wrapper for ClearSilver CGI */
> int read_cb(void *ptr, char *data, int size)
> {
> UNUSED(ptr);
>
> return FCGI_fread(data, sizeof(char), size, FCGI_stdin);
> }
>
> /* FCGI_vprintf wrapper for ClearSilver CGI */
> int writef_cb(void *ptr, const char *format, va_list ap)
> {
> UNUSED(ptr);
>
> return FCGI_vprintf(format, ap);
> }
>
> /* FCGI_fwrite wrapper for ClearSilver CGI */
> int write_cb(void *ptr, const char *data, int size)
> {
> UNUSED(ptr);
>
> return FCGI_fwrite((void *) data, sizeof(char), size, FCGI_stdout);
> }
>
> and then I call:
>
> cgiwrap_init_emu(NULL, &read_cb, &writef_cb, &write_cb, NULL, NULL,
NULL);
>
> The error I get is:
>
> in cgiwrap.c:0192:cgiwrap_writevf - writef_cb returned 27: [134]
> Transport endpoint is not connected
>
>
> Then I had a look at cgi/fcgi_hello.c and saw this line (by the way, I
> think 'environ' should be replaced by 'envp' in this line):
>
> cgiwrap_init_std(argc, argv, environ);
>
> and added this line to my code before the call to cgiwrap_init_emu, but
> I still have the same error.
>
> Then I've tried using the following from cgi/fcgi_hello.c instead:
>
> int cs_printf(void *ctx, const char *s, va_list args)
> {
> UNUSED(ctx);
>
> return printf(s, args);
> }
>
> int cs_write(void *ctx, const char *s, int n)
> {
> UNUSED(ctx);
>
> return fwrite(s, n, 1, FCGI_stdout);
> }
>
> and calling this:
>
> cgiwrap_init_emu(NULL, NULL, cs_printf, cs_write, NULL, NULL, NULL);
>
> but it makes things worse as this gives me 2 errors then:
>
> in cgiwrap.c:0192:cgiwrap_writevf - writef_cb returned 27: [134]
> Transport endpoint is not connected
>
> in cgiwrap.c:0210:cgiwrap_write - write_cb returned 1<2488: [134]
> Transport endpoint is not connected
>
>
> --Raphael
>
> >> On 08/02/07 Raphaël HUCK uttered the following other thing:
> >>> I've made a simple example to try and understand where these
leaks come
> >>> from:
> >>>
> >>> void fcgi_begin(void)
> >>> {
> >>> NEOERR *err;
> >>>
> >>> err = cgi_init(&cgi, NULL);
> >>> nerr_ignore(&err);
> >>> }
> >>>
> >>> void fcgi_end(void)
> >>> {
> >>> cgi_destroy(&cgi);
> >>> }
> >>>
> >>> void fcgi_dispatch(void)
> >>> {
> >>> NEOERR *err;
> >>>
> >>> err = hdf_read_file(cgi->hdf, "test.hdf");
> >>> nerr_ignore(&err);
> >>>
> >>> err = cgi_display(cgi, "test.cst");
> >>> nerr_ignore(&err);
> >>>
> >>> return;
> >>> }
> >>>
> >>> int main(int argc, char **argv)
> >>> {
> >>> UNUSED(argc);
> >>> UNUSED(argv);
> >>>
> >>> while (FCGI_Accept() >= 0)
> >>> {
> >>> #ifdef DMALLOC
> >>> unsigned long mark;
> >>> /* get the current dmalloc position */
> >>> mark = dmalloc_mark();
> >>> #endif
> >>>
> >>> fcgi_begin();
> >>> fcgi_dispatch();
> >>> fcgi_end();
> >>>
> >>> #ifdef DMALLOC
> >>> /*
> >>> * log unfreed pointers that have been added to
> >>> * the heap since mark
> >>> */
> >>> dmalloc_log_changed(mark,
> >>> 1 /* log unfreed pointers */,
> >>> 0 /* do not log freed pointers */,
> >>> 1 /* log each pnt otherwise summary */);
> >>> #endif
> >>> }
> >>>
> >>> return 0;
> >>> }
> >>>
> >>> And I get the following results with dmalloc:
> >>>
> >>> $ dmalloc_summarize.pl fastcgi < fastcgi.3393
> >>> size count gross function
> >>> 37 10036 total
> >>> 284 35 9940 ra=0x419748
> >>> 80 1 80 _err_alloc+64> and ends at
0x41974c
> >>> <_err_alloc [neo_err.c:59]
> >>> 16 1 16 check_resize+76> and ends at
0x41b8d8
> >>> <check_resize [ulist.c:37]
> >>>
> >>>
> >>>
> >>> --Raphael
> >>>
> >>>> Anything that returns a NEOERR is allocating memory on error.
You must
> >>>> check the return value and call one of the methods to free the
data,
> >>>> usually one of:
> >>>>
> >>>> nerr_log_error
> >>>> nerr_ignore
> >>>> nerr_handle
> >>>>
> >>>> See util/neo_err.h for details.
> >>>>
> >>>> The uListInit one is probably from nerr_init, which allocates a
very
> >>>> small amount of memory once.
> >>>>
> >>>> Brandon
> >>>>
> >>>> On 07/31/07 raphael.huck uttered the following other thing:
> >>>>> Hi,
> >>>>>
> >>>>> Here's what I've found with DMALLOC:
> >>>>>
> >>>>> $ dmalloc_summarize.pl fastcgi < fastcgi.10983
> >>>>> size count gross function
> >>>>> 1494 401044 total
> >>>>> 284 1364 387376 ra=0x436818
> >>>>> 1176 9 10584 _err_alloc+64> and ends at
0x43681c
> >>>>> <_err_alloc [neo_err.c:59]
> >>>>> 240 2 480 hcreate_r
> >>>>> 16 4 64 check_resize+76> and ends at
> >>>>> 0x4389a8 <check_resize [ulist.c:37]
> >>>>> 20 3 60 uListInit+68> and ends at
0x438a5c
> >>>>> <uListInit [ulist.c:61]
> >>>>>
> >>>>>
> >>>>>
> >>>>> The part which leaks the most memory is around 0x436818, which is:
> >>>>>
> >>>>> $ mips-linux-objdump -S fastcgi | grep -A 21 -B 25 436818
> >>>>> static NEOERR *_err_alloc(void)
> >>>>> {
> >>>>> 4367d0: 3c1c0fbd lui gp,0xfbd
> >>>>> 4367d4: 279c2c10 addiu gp,gp,11280
> >>>>> 4367d8: 0399e021 addu gp,gp,t9
> >>>>> 4367dc: 27bdffe0 addiu sp,sp,-32
> >>>>> 4367e0: afbf0018 sw ra,24(sp)
> >>>>> 4367e4: afbc0010 sw gp,16(sp)
> >>>>> NEOERR *err;
> >>>>>
> >>>>> if (!UseFreeList || FreeList == NULL)
> >>>>> 4367e8: 8f828018 lw v0,-32744(gp)
> >>>>> 4367ec: 8f878018 lw a3,-32744(gp)
> >>>>> {
> >>>>> err = (NEOERR *)calloc (1, sizeof (NEOERR));
> >>>>> 4367f0: 8f9988dc lw t9,-30500(gp)
> >>>>> 4367f4: 8c4325d0 lw v1,9680(v0)
> >>>>> 4367f8: 2405011c li a1,284
> >>>>> 4367fc: 10600004 beqz v1,436810 <_err_alloc+0x40>
> >>>>> 436800: 24040001 li a0,1
> >>>>> 436804: 8ce625cc lw a2,9676(a3)
> >>>>> 436808: 14c0000d bnez a2,436840 <_err_alloc+0x70>
> >>>>> 43680c: 8fbf0018 lw ra,24(sp)
> >>>>> 436810: 0320f809 jalr t9
> >>>>> 436814: 00000000 nop
> >>>>> 436818: 8fbc0010 lw gp,16(sp)
> >>>>> if (err == NULL)
> >>>>> {
> >>>>> ne_warn ("INTERNAL ERROR: Unable to allocate memory for
> >>>>> NEOERR");
> >>>>> return INTERNAL_ERR;
> >>>>> }
> >>>>> return err;
> >>>>> 43681c: 00402821 move a1,v0
> >>>>> 436820: 8f848024 lw a0,-32732(gp)
> >>>>> 436824: 8f998aa4 lw t9,-30044(gp)
> >>>>> 436828: 1040000f beqz v0,436868 <_err_alloc+0x98>
> >>>>> 43682c: 24844130 addiu a0,a0,16688
> >>>>> }
> >>>>> else
> >>>>> {
> >>>>> err = FreeList;
> >>>>> FreeList = FreeList->next;
> >>>>> }
> >>>>> err->flags |= NE_IN_USE;
> >>>>> err->next = NULL;
> >>>>> return err;
> >>>>> }
> >>>>>
> >>>>> These seem to be memory leaks. Can anyone confirm?
> >>>>>
> >>>>> --Raphaël HUCK
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>> Yahoo! Groups Links
> >>>>>
> >>>>>
> >>>>>
> >
> >
> >
> >
> > Yahoo! Groups Links
> >
> >
> >
>