This is the mail archive of the libc-alpha@sources.redhat.com 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]
Other format: [Raw text]

Re: Random failures when calling free()/malloc()


On Sat, 2003-07-19 at 22:18, Dan Kegel wrote:
> Martin Schlemmer wrote:
> > On Sat, 2003-07-19 at 18:39, Dan Kegel wrote:
> > 
> >>BTW, have you cranked glibc's malloc debugging setting
> >>up to the max?  There's also a sanity check routine you
> >>could call periodically before the failure...
> > 
> > 
> > Ok, got this:
> > 
> > --------------------------------------
> > malloc.c:3212: munmap_chunk: Assertion `((p->prev_size + size) &
> > (mp_.pagesize-1)) == 0' failed.
> > --------------------------------------
> > 
> > Pretty much the same as the rest, just ending in the assert and not
> > the unlink().
> 
> Run that in gdb and let's see a backtrace...

Lets take unicode-collate from glib-2.2.2:

-----------------------------------------------------
GNU gdb 5.3
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for
details.
This GDB was configured as "i686-pc-linux-gnu"...
(gdb) r utf8.txt
Starting program: /usr/src/glib-2.2.2/tests/.libs/unicode-collate
utf8.txt
unicode-collate: malloc.c:3212: munmap_chunk: Assertion `((p->prev_size
+ size) & (mp_.pagesize-1)) == 0' failed.
 
Program received signal SIGABRT, Aborted.
0xffffe410 in ?? ()
(gdb) bt
#0  0xffffe410 in ?? ()
#1  0x400c76d3 in *__GI_abort () at ../sysdeps/generic/abort.c:88
#2  0x400bfbef in *__GI___assert_fail (assertion=0x6 <Address 0x6 out of
bounds>, file=0x6 <Address 0x6 out of bounds>, line=6,
    function=0x401c8c34 "@?\022") at assert.c:83
#3  0x4010fd85 in munmap_chunk (p=0x1f88) at malloc.c:3221
#4  0x400563d9 in g_free (mem=0x804bdc0) at gmem.c:186
#5  0x400742d9 in g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:211
#6  0x08048956 in main (argc=2, argv=0xbffff284) at unicode-collate.c:71
#7  0x400b36f5 in __libc_start_main (main=0x804882a <main>, argc=2,
ubp_av=0xbffff284, init=0x8048ab0 <__libc_csu_init>, fini=0x8048b10
<__libc_csu_fini>,
    rtld_fini=0x20, stack_end=0x6) at
../sysdeps/generic/libc-start.c:205
(gdb)
-----------------------------------------

> Also, can you refresh our memory on exactly how to reproduce
> this bug?  A step-by-step recipe, leaving nothing out,
> would be helpful.  It ought to show the environment
> variable you set to turn on malloc checking, too,
> as well as the patch you applied to add the calls
> to mcheck() or whatever.

Nothing serious - get a 2.5/6 kernel running, compile and install
latest cvs glibc+nptl-0.53 and run what I must confess looks to
be mostly things that use glib-2.2.x.

Toolchain:

gcc-3.3 (latest gcc-3_3-rhl-branch branch)
binutils-2.14.90.0.4.1 (with RH patches)
glibc-2.3.2-200307latest
nptl-0.53

This has worked fine for some time until about a month ago that I
started to run into issues, although some of them was just to get
gcc play nice with the cleanup stuff that was added.

I can leave everything as is, and just revert glibc+nptl to a
20030517 snapshot with nptl-0.39, and it works fine.

I did try with different C[XX]FLAGS, none at all, only with '-ggdb',
no difference.

If you look at glib-2.2.2/tests/unicode-collate.c, which is the most
simple example I can think of now, it calls g_utf8_collate_key(),
which works fine the first call, but burn on the second call.  The
function looks like follow:

------------------g_utf8_collate_key()-------------------
gchar *
g_utf8_collate_key (const gchar *str,
                    gssize       len)
{
  gchar *result;
  size_t xfrm_len;
                                                                                                                                                            
#ifdef __STDC_ISO_10646__
                                                                                                                                                            
  gunichar *str_norm;
  wchar_t *result_wc;
  size_t i;
  size_t result_len = 0;
                                                                                                                                                            
  g_return_val_if_fail (str != NULL, NULL);
                                                                                                                                                            
  str_norm = _g_utf8_normalize_wc (str, len, G_NORMALIZE_ALL_COMPOSE);
                                                                                                                                                            
  setlocale (LC_COLLATE, "");
                                                                                                                                                            
  xfrm_len = wcsxfrm (NULL, (wchar_t *)str_norm, 0);
  result_wc = g_new (wchar_t, xfrm_len + 1);
  if (!result_wc)
        return NULL;
  wcsxfrm (result_wc, (wchar_t *)str_norm, xfrm_len + 1);
 
  for (i=0; i < xfrm_len; i++)
    result_len += utf8_encode (NULL, result_wc[i]);
 
  result = g_malloc (result_len + 1);
  result_len = 0;
  for (i=0; i < xfrm_len; i++)
    result_len += utf8_encode (result + result_len, result_wc[i]);
 
  result[result_len] = '\0';
 
  g_free (result_wc);
  g_free (str_norm);
 
  return result;
#else /* !__STDC_ISO_10646__ */

  const gchar *charset;
  gchar *str_norm;

  g_return_val_if_fail (str != NULL, NULL);

  str_norm = g_utf8_normalize (str, len, G_NORMALIZE_ALL_COMPOSE);

  if (g_get_charset (&charset))
    {
      xfrm_len = strxfrm (NULL, str_norm, 0);
      result = g_malloc (xfrm_len + 1);
      strxfrm (result, str_norm, xfrm_len + 1);
    }
  else
    {
      gchar *str_locale = g_convert (str_norm, -1, "UTF-8", charset,
NULL, NULL, NULL);

      if (str_locale)
    {
      xfrm_len = strxfrm (NULL, str_locale, 0);
      result = g_malloc (xfrm_len + 2);
      result[0] = 'A';
      strxfrm (result + 1, str_locale, xfrm_len + 1);

      g_free (str_locale);
    }
      else
    {
      xfrm_len = strlen (str_norm);
      result = g_malloc (xfrm_len + 2);
      result[0] = 'B';
      memcpy (result + 1, str_norm, xfrm_len);
      result[xfrm_len+1] = '\0';
    }
    }

  g_free (str_norm);
#endif /* __STDC_ISO_10646__ */

  return result;
}
---------------------------------------------------------

Now, I do not know why I have not thought about it earlier,
but over here __STDC_ISO_10646__ is defined in features.h.

I removed that an hour or so back, and now everthing is
working fine :P

Anyhow, I did try to do an 'extended' debugging session:

----------------------------------------------------------
GNU gdb 5.3
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for
details.
This GDB was configured as "i686-pc-linux-gnu"...
(gdb) r utf8.txt
Starting program: /usr/src/glib-2.2.2/tests/.libs/unicode-collate
utf8.txt
unicode-collate: malloc.c:3212: munmap_chunk: Assertion `((p->prev_size
+ size) & (mp_.pagesize-1)) == 0' failed.
                                                                                                                                                            
Program received signal SIGABRT, Aborted.
0xffffe410 in ?? ()
(gdb) bt
#0  0xffffe410 in ?? ()
#1  0x400c76d3 in *__GI_abort () at ../sysdeps/generic/abort.c:88
#2  0x400bfbef in *__GI___assert_fail (assertion=0x6 <Address 0x6 out of
bounds>, file=0x6 <Address 0x6 out of bounds>, line=6,
    function=0x401c8c34 "@?\022") at assert.c:83
#3  0x4010fd85 in munmap_chunk (p=0x1e89) at malloc.c:3221
#4  0x40045419 in g_free (mem=0x804bdc0) at gmem.c:186
#5  0x4006335a in g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:225
#6  0x08048956 in main (argc=2, argv=0xbffff1c4) at unicode-collate.c:71
#7  0x400b36f5 in __libc_start_main (main=0x804882a <main>, argc=2,
ubp_av=0xbffff1c4, init=0x8048ab0 <__libc_csu_init>,
    fini=0x8048b10 <__libc_csu_fini>, rtld_fini=0x20, stack_end=0x6) at
../sysdeps/generic/libc-start.c:205
(gdb) break g_utf8_collate_key
Breakpoint 1 at 0x400631be: file gunicollate.c, line 201.
(gdb) break gunicollate.c:225
Breakpoint 2 at 0x4006334f: file gunicollate.c, line 225.
(gdb) r utf8.txt
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /usr/src/glib-2.2.2/tests/.libs/unicode-collate
utf8.txt
                                                                                                                                                            
Breakpoint 1, g_utf8_collate_key (str=0x804bd60 "# This file is derived
from ", len=-1) at gunicollate.c:201
201       size_t result_len = 0;
(gdb) n
203       g_return_val_if_fail (str != NULL, NULL);
(gdb) n
205       str_norm = _g_utf8_normalize_wc (str, len,
G_NORMALIZE_ALL_COMPOSE);
(gdb) n
207       setlocale (LC_COLLATE, "");
(gdb) n
209       xfrm_len = wcsxfrm (NULL, (wchar_t *)str_norm, 0);
(gdb) n
210       result_wc = g_new (wchar_t, xfrm_len + 1);
(gdb) n
211       if (!result_wc)
(gdb) print xfrm_len
$1 = 28
(gdb) print result_wc
$2 = (wchar_t *) 0x804be00
(gdb) c
Continuing.
                                                                                                                                                            
Breakpoint 2, g_utf8_collate_key (str=0x804bd60 "# This file is derived
from ", len=-1) at gunicollate.c:225
225       g_free (result_wc);
(gdb) print result_wc
$3 = (wchar_t *) 0x804be00
(gdb) c
Continuing.
                                                                                                                                                            
Breakpoint 1, g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:201
201       size_t result_len = 0;
(gdb) n
203       g_return_val_if_fail (str != NULL, NULL);
(gdb) n
205       str_norm = _g_utf8_normalize_wc (str, len,
G_NORMALIZE_ALL_COMPOSE);
(gdb) n
207       setlocale (LC_COLLATE, "");
(gdb) n
209       xfrm_len = wcsxfrm (NULL, (wchar_t *)str_norm, 0);
(gdb) n
210       result_wc = g_new (wchar_t, xfrm_len + 1);
(gdb) n
211       if (!result_wc)
(gdb) print xfrm_len
$4 = 1
(gdb) print result_wc
$5 = (wchar_t *) 0x804bdc0
(gdb) c
Continuing.
 
Breakpoint 2, g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:225
225       g_free (result_wc);
(gdb) print result_wc
$6 = (wchar_t *) 0x804bdc0
(gdb) s
g_free (mem=0x804bdc0) at gmem.c:185
185       if (mem)
(gdb) s
186         glib_mem_vtable.free (mem);
(gdb) s
__libc_free (mem=0x8048b10) at malloc.c:3324
3324      void (*hook) __MALLOC_P ((__malloc_ptr_t, __const
__malloc_ptr_t)) =
(gdb) print mem
$7 = (void *) 0x8048b10
(gdb) s
3320    {
(gdb) print mem
$8 = (void *) 0x8048b10
(gdb) s
3324      void (*hook) __MALLOC_P ((__malloc_ptr_t, __const
__malloc_ptr_t)) =
(gdb) print mem
$9 = (void *) 0x804bdc0
(gdb) s
3326      if (hook != NULL) {
(gdb) s
3331      if (mem == 0)                              /* free(0) has no
effect */
(gdb) s
3334      p = mem2chunk(mem);
(gdb) print mem
$10 = (void *) 0x804bdc0
(gdb) print p
$11 = 0x401c9564
(gdb) s
3337      if (chunk_is_mmapped(p))                       /* release
mmapped memory. */
(gdb) s
3339        munmap_chunk(p);
(gdb) print p
$12 = 0x804bdb8
(gdb) s
munmap_chunk (p=0x804be98) at malloc.c:3203
3203    {
(gdb) print p
$13 = 0x804be98
(gdb) s
munmap_chunk (p=0x804bdb8) at malloc.c:3204
3204      INTERNAL_SIZE_T size = chunksize(p);
(gdb) print p
$14 = 0x804bdb8
(gdb) s
3203    {
(gdb) print size
$15 = 1073832320
(gdb) s
3204      INTERNAL_SIZE_T size = chunksize(p);
(gdb) s
3207      assert (chunk_is_mmapped(p));
(gdb) print size
$16 = 32
(gdb) s
3212      assert(((p->prev_size + size) & (mp_.pagesize-1)) == 0);
(gdb) print (p->prev_size + size) & (mp_.pagesize-1)
$17 = 137
(gdb) print p
$18 = 0x804bdb8
(gdb) print p->prev_size
$19 = 105
(gdb) print size
$20 = 32
(gdb) print mp_
$21 = {trim_threshold = 131072, top_pad = 131072, mmap_threshold =
131072, n_mmaps = 0, n_mmaps_max = 65536, max_n_mmaps = 0, pagesize =
4096,
  mmapped_mem = 0, max_mmapped_mem = 0, max_total_mem = 0, sbrk_base =
0x804a000 ""}
(gdb) print mp_.pagesize
$22 = 4096
(gdb) s
0x4010fd85      3221    }
(gdb) s
*__GI___assert_fail (assertion=0x89 <Address 0x89 out of bounds>,
file=0x89 <Address 0x89 out of bounds>, line=137, function=0x401bc2e8
"munmap_chunk")
    at assert.c:53
53        FATAL_PREPARE;
(gdb) n
56        if (__asprintf (&buf, _("%s%s%s:%u: %s%sAssertion `%s'
failed.\n"),
(gdb) n
64            if (_IO_fwide (stderr, 0) > 0)
(gdb) n
68              (void) fputs (buf, stderr);
(gdb) n
unicode-collate: malloc.c:3212: munmap_chunk: Assertion `((p->prev_size
+ size) & (mp_.pagesize-1)) == 0' failed.
70            (void) fflush (stderr);
(gdb) c
Continuing.
 
Program received signal SIGABRT, Aborted.
0xffffe410 in ?? ()
(gdb)
----------------------------------------------------------

Anything that changed with unicode/whatever handling that might
cause this ?

The following is just with the last call to g_utf8_collate_key()
that segfaults.  I tried to see if there was an extra call to
__libc_free() ....

----------------------------------------------------------
azarah@nosferatu azarah $ cat tmp/glib-segfault-4.log
(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x4006314f in g_utf8_collate_key at
gunicollate.c:189
        breakpoint already hit 2 times
3   breakpoint     keep y   0x400453c5 in g_free at gmem.c:185
        breakpoint already hit 3 times
        print mem
        bt
4   breakpoint     keep y   0x40110117 in __libc_free at malloc.c:3324
        breakpoint already hit 6 times
5   breakpoint     keep y   0x40045251 in g_malloc at gmem.c:137
        breakpoint already hit 18 times
        print mem
        bt
6   breakpoint     keep y   0x40110125 in __libc_free at malloc.c:3326
        breakpoint already hit 5 times
        print mem
        bt
(gdb) c
Breakpoint 1, g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:189
189       size_t result_len = 0;
(gdb) c
Continuing.
 
Breakpoint 5, g_malloc (n_bytes=8) at gmem.c:137
137           if (mem)
$100 = 0x804bdb0
#0  g_malloc (n_bytes=8) at gmem.c:137
#1  0x40063b9f in _g_utf8_normalize_wc (str=0x804bda0 "#", max_len=-1,
mode=G_NORMALIZE_ALL_COMPOSE) at gunidecomp.c:272
#2  0x400631ca in g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:193
#3  0x08048956 in main (argc=2, argv=0xbfffe7b4) at unicode-collate.c:71
#4  0x400b36f5 in __libc_start_main (main=0x804882a <main>, argc=2,
ubp_av=0xbfffe7b4, init=0x8048ab0 <__libc_csu_init>,
    fini=0x8048b10 <__libc_csu_fini>, rtld_fini=0x40016180
<_rtld_local>, stack_end=0x804be70) at
../sysdeps/generic/libc-start.c:205
(gdb) c
Continuing.
 
Breakpoint 4, __libc_free (mem=0x401b3841) at malloc.c:3324
3324      void (*hook) __MALLOC_P ((__malloc_ptr_t, __const
__malloc_ptr_t)) =
(gdb) c
Continuing.
 
Breakpoint 6, __libc_free (mem=0x0) at malloc.c:3326
3326      if (hook != NULL) {
$101 = (void *) 0x0
#0  __libc_free (mem=0x0) at malloc.c:3326
#1  0x400bd374 in *__GI_setlocale (category=3, locale=0x4007c09e "") at
setlocale.c:431
#2  0x400631e3 in g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:195
#3  0x08048956 in main (argc=2, argv=0xbfffe7b4) at unicode-collate.c:71
#4  0x400b36f5 in __libc_start_main (main=0x804882a <main>, argc=2,
ubp_av=0xbfffe7b4, init=0x8048ab0 <__libc_csu_init>,
    fini=0x8048b10 <__libc_csu_fini>, rtld_fini=0x40016180
<_rtld_local>, stack_end=0x0) at ../sysdeps/generic/libc-start.c:205
(gdb) c
Continuing.
 
Breakpoint 5, g_malloc (n_bytes=8) at gmem.c:137
137           if (mem)
$102 = 0x804bdc0
#0  g_malloc (n_bytes=8) at gmem.c:137
#1  0x40063212 in g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:198
#2  0x08048956 in main (argc=2, argv=0xbfffe7b4) at unicode-collate.c:71
#3  0x400b36f5 in __libc_start_main (main=0x804882a <main>, argc=2,
ubp_av=0xbfffe7b4, init=0x8048ab0 <__libc_csu_init>,
    fini=0x8048b10 <__libc_csu_fini>, rtld_fini=0x40016180
<_rtld_local>, stack_end=0x804be70) at
../sysdeps/generic/libc-start.c:205
(gdb) c
Continuing.
 
Breakpoint 5, g_malloc (n_bytes=2) at gmem.c:137
137           if (mem)
$103 = 0x804bdd0
#0  g_malloc (n_bytes=2) at gmem.c:137
#1  0x4006327a in g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:204
#2  0x08048956 in main (argc=2, argv=0xbfffe7b4) at unicode-collate.c:71
#3  0x400b36f5 in __libc_start_main (main=0x804882a <main>, argc=2,
ubp_av=0xbfffe7b4, init=0x8048ab0 <__libc_csu_init>,
    fini=0x8048b10 <__libc_csu_fini>, rtld_fini=0x40016180
<_rtld_local>, stack_end=0x804be70) at
../sysdeps/generic/libc-start.c:205
(gdb) c
Continuing.
 
Breakpoint 3, g_free (mem=0x804bdc0) at gmem.c:185
185       if (mem)
$104 = 0x804bdc0
#0  g_free (mem=0x804bdc0) at gmem.c:185
#1  0x400632d9 in g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:211
#2  0x08048956 in main (argc=2, argv=0xbfffe7b4) at unicode-collate.c:71
#3  0x400b36f5 in __libc_start_main (main=0x804882a <main>, argc=2,
ubp_av=0xbfffe7b4, init=0x8048ab0 <__libc_csu_init>,
    fini=0x8048b10 <__libc_csu_fini>, rtld_fini=0x40016180
<_rtld_local>, stack_end=0x1) at ../sysdeps/generic/libc-start.c:205
(gdb) s
186         glib_mem_vtable.free (mem);
(gdb) s
 
Breakpoint 4, __libc_free (mem=0x8048b10) at malloc.c:3324
3324      void (*hook) __MALLOC_P ((__malloc_ptr_t, __const
__malloc_ptr_t)) =
(gdb) s
3320    {
(gdb) s
3324      void (*hook) __MALLOC_P ((__malloc_ptr_t, __const
__malloc_ptr_t)) =
(gdb) s
 
Breakpoint 6, __libc_free (mem=0x804bdc0) at malloc.c:3326
3326      if (hook != NULL) {
$105 = (void *) 0x804bdc0
#0  __libc_free (mem=0x804bdc0) at malloc.c:3326
#1  0x400453d9 in g_free (mem=0x804bdc0) at gmem.c:186
#2  0x400632d9 in g_utf8_collate_key (str=0x804bda0 "#", len=-1) at
gunicollate.c:211
#3  0x08048956 in main (argc=2, argv=0xbfffe7b4) at unicode-collate.c:71
#4  0x400b36f5 in __libc_start_main (main=0x804882a <main>, argc=2,
ubp_av=0xbfffe7b4, init=0x8048ab0 <__libc_csu_init>, fini=0x804bdc0,
    rtld_fini=0x40016180 <_rtld_local>, stack_end=0x0) at
../sysdeps/generic/libc-start.c:205
(gdb) s
3331      if (mem == 0)                              /* free(0) has no
effect */
(gdb) s
3334      p = mem2chunk(mem);
(gdb) s
3337      if (chunk_is_mmapped(p))                       /* release
mmapped memory. */
(gdb) s
3339        munmap_chunk(p);
(gdb) s
munmap_chunk (p=0x804be98) at malloc.c:3203
3203    {
(gdb) s
munmap_chunk (p=0x804bdb8) at malloc.c:3204
3204      INTERNAL_SIZE_T size = chunksize(p);
(gdb) s
3203    {
(gdb) s
3204      INTERNAL_SIZE_T size = chunksize(p);
(gdb) s
3207      assert (chunk_is_mmapped(p));
(gdb) s
3212      assert(((p->prev_size + size) & (mp_.pagesize-1)) == 0);
(gdb) s
0x4010fd85      3221    }
(gdb) s
*__GI___assert_fail (assertion=0x89 <Address 0x89 out of bounds>,
file=0x89 <Address 0x89 out of bounds>, line=137, function=0x401bc2e8
"munmap_chunk")
    at assert.c:53
53        FATAL_PREPARE;
(gdb)
----------------------------------------------------------

But it does not look that way - address 0x804bdc0 gets allocated,
and then the first time it is free'd:

  assert(((p->prev_size + size) & (mp_.pagesize-1)) == 0);

fails.


Thanks,

-- 

Martin Schlemmer



Attachment: signature.asc
Description: This is a digitally signed message part


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