? valgrind2.diff
? glib/.gslice.c.swp
? glib/contrib
? tests/.slice-test.c.swp
Index: configure.in
===================================================================
RCS file: /cvs/gnome/glib/configure.in,v
retrieving revision 1.508
diff -u -p -d -r1.508 configure.in
--- configure.in	15 May 2006 17:40:38 -0000	1.508
+++ configure.in	17 May 2006 06:34:35 -0000
@@ -2796,6 +2796,7 @@ build/win32/vs8/Makefile
 glib/Makefile
 glib/libcharset/Makefile
 glib/gnulib/Makefile
+glib/contrib/Makefile
 gmodule/Makefile
 gmodule/gmoduleconf.h
 gobject/Makefile
Index: docs/reference/glib/tmpl/glib-unused.sgml
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/glib/tmpl/glib-unused.sgml,v
retrieving revision 1.39
diff -u -p -d -r1.39 glib-unused.sgml
--- docs/reference/glib/tmpl/glib-unused.sgml	5 May 2005 14:57:27 -0000	1.39
+++ docs/reference/glib/tmpl/glib-unused.sgml	17 May 2006 06:34:35 -0000
@@ -203,6 +203,15 @@ error domains.
 </para>
 
 
+<!-- ##### MACRO G_HAVE_GNUC_VISIBILITY ##### -->
+<para>
+This macro is defined as 1 if the the compiler supports ELF visibility 
+attributes (currently only <command>gcc</command>).
+</para>
+
+Since: 2.6
+
+
 <!-- ##### MACRO G_HOOK_DEFERRED_DESTROY ##### -->
 <para>
 
Index: docs/reference/glib/tmpl/macros_misc.sgml
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/glib/tmpl/macros_misc.sgml,v
retrieving revision 1.57
diff -u -p -d -r1.57 macros_misc.sgml
--- docs/reference/glib/tmpl/macros_misc.sgml	9 Dec 2005 18:05:21 -0000	1.57
+++ docs/reference/glib/tmpl/macros_misc.sgml	17 May 2006 06:34:35 -0000
@@ -297,16 +297,6 @@ See the GNU C documentation for details.
 
 
 
-<!-- ##### MACRO G_HAVE_GNUC_VISIBILITY ##### -->
-<para>
-This macro is defined as 1 if the the compiler supports ELF visibility 
-attributes (currently only <command>gcc</command>).
-</para>
-
-Since: 2.6
-
-
-
 <!-- ##### MACRO G_GNUC_INTERNAL ##### -->
 <para>
 Expands to the GNU C <literal>visibility(hidden)</literal> attribute if the 
Index: docs/reference/glib/tmpl/messages.sgml
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/glib/tmpl/messages.sgml,v
retrieving revision 1.39
diff -u -p -d -r1.39 messages.sgml
--- docs/reference/glib/tmpl/messages.sgml	15 May 2006 17:16:22 -0000	1.39
+++ docs/reference/glib/tmpl/messages.sgml	17 May 2006 06:34:35 -0000
@@ -118,6 +118,8 @@ A convenience function/macro to log a no
 
 @...:
 
+@...:
+
 @...: 
 
 
@@ -130,6 +132,8 @@ A convenience function/macro to log a wa
 
 @...:
 
+@...:
+
 @...: 
 
 
@@ -146,6 +150,8 @@ example.
 
 @...:
 
+@...:
+
 @...: 
 
 
@@ -163,6 +169,8 @@ assertion failure.
 
 @...:
 
+@...:
+
 @...: 
 
 
@@ -172,6 +180,8 @@ A convenience function/macro to log a de
 </para>
 
 @...: format string, followed by parameters to insert into the format string (as with printf())
+
+@...:
 
 @...:
 
Index: docs/reference/glib/tmpl/string_utils.sgml
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/glib/tmpl/string_utils.sgml,v
retrieving revision 1.42
diff -u -p -d -r1.42 string_utils.sgml
--- docs/reference/glib/tmpl/string_utils.sgml	3 May 2006 02:04:54 -0000	1.42
+++ docs/reference/glib/tmpl/string_utils.sgml	17 May 2006 06:34:35 -0000
@@ -644,6 +644,17 @@ For that purpose, use g_utf8_strreverse(
 @Returns: the same pointer passed in as @string.
 
 
+<!-- ##### FUNCTION g_ascii_strtoll ##### -->
+<para>
+
+</para>
+
+@nptr: 
+@endptr: 
+@base: 
+@Returns: 
+
+
 <!-- ##### FUNCTION g_ascii_strtoull ##### -->
 <para>
 
Index: glib/Makefile.am
===================================================================
RCS file: /cvs/gnome/glib/glib/Makefile.am,v
retrieving revision 1.142
diff -u -p -d -r1.142 Makefile.am
--- glib/Makefile.am	10 May 2006 00:44:49 -0000	1.142
+++ glib/Makefile.am	17 May 2006 06:34:35 -0000
@@ -6,9 +6,9 @@ PRINTF_SUBDIR = gnulib
 printf_la = gnulib/libgnulib.la
 endif 
 
-SUBDIRS = libcharset $(PRINTF_SUBDIR)
+SUBDIRS = libcharset $(PRINTF_SUBDIR) contrib
 
-DIST_SUBDIRS = libcharset gnulib
+DIST_SUBDIRS = libcharset gnulib contrib
 
 INCLUDES = -I$(top_srcdir) -DG_LOG_DOMAIN=\"GLib\" \
 	$(GLIB_DEBUG_FLAGS) -DG_DISABLE_DEPRECATED -DGLIB_COMPILATION 
Index: glib/garray.c
===================================================================
RCS file: /cvs/gnome/glib/glib/garray.c,v
retrieving revision 1.37
diff -u -p -d -r1.37 garray.c
--- glib/garray.c	25 Jan 2006 15:51:43 -0000	1.37
+++ glib/garray.c	17 May 2006 06:34:35 -0000
@@ -42,6 +42,7 @@
 
 #include "galias.h"
 
+#include "contrib/memcheck.h"
 
 #define MIN_ARRAY_SIZE  16
 
@@ -67,8 +68,11 @@ struct _GRealArray
 }G_STMT_END
 
 static gint g_nearest_pow        (gint        num) G_GNUC_CONST;
-static void g_array_maybe_expand (GRealArray *array,
-				  gint        len);
+
+static void g_array_expand_prepare (GRealArray *array,
+				    gint        len);
+static void g_array_shrink (GRealArray *array,
+			    gint        len);
 
 GArray*
 g_array_new (gboolean zero_terminated,
@@ -94,7 +98,20 @@ GArray* g_array_sized_new (gboolean zero
 
   if (array->zero_terminated || reserved_size != 0)
     {
-      g_array_maybe_expand (array, reserved_size);
+      guint want_alloc = g_nearest_pow (g_array_elt_len (array, zero_terminated+reserved_size));
+      guint want_len = zero_terminated ? elt_size : 0;
+
+      want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE);
+
+      array->data = g_malloc (want_alloc);
+      array->alloc = want_alloc;
+
+      if (G_UNLIKELY (g_mem_gc_friendly))
+        memset (array->data, 0, want_alloc);
+
+      if (G_UNLIKELY (g_mem_checker_running))
+	VALGRIND_MAKE_NOACCESS(array->data + want_len, want_alloc - want_len);
+
       g_array_zero_terminate(array);
     }
 
@@ -129,7 +146,7 @@ g_array_append_vals (GArray       *farra
 {
   GRealArray *array = (GRealArray*) farray;
 
-  g_array_maybe_expand (array, len);
+  g_array_expand_prepare (array, len);
 
   memcpy (g_array_elt_pos (array, array->len), data, 
 	  g_array_elt_len (array, len));
@@ -148,7 +165,7 @@ g_array_prepend_vals (GArray        *far
 {
   GRealArray *array = (GRealArray*) farray;
 
-  g_array_maybe_expand (array, len);
+  g_array_expand_prepare (array, len);
 
   g_memmove (g_array_elt_pos (array, len), g_array_elt_pos (array, 0), 
 	     g_array_elt_len (array, array->len));
@@ -170,7 +187,7 @@ g_array_insert_vals (GArray        *farr
 {
   GRealArray *array = (GRealArray*) farray;
 
-  g_array_maybe_expand (array, len);
+  g_array_expand_prepare (array, len);
 
   g_memmove (g_array_elt_pos (array, len + index), 
 	     g_array_elt_pos (array, index), 
@@ -192,13 +209,13 @@ g_array_set_size (GArray *farray,
   GRealArray *array = (GRealArray*) farray;
   if (length > array->len)
     {
-      g_array_maybe_expand (array, length - array->len);
+      g_array_expand_prepare (array, length - array->len);
       
       if (array->clear)
 	g_array_elt_zero (array, array->len, length - array->len);
     }
-  else if (G_UNLIKELY (g_mem_gc_friendly) && length < array->len)
-    g_array_elt_zero (array, length, array->len - length);
+  else if (length < array->len)
+    g_array_shrink (array, array->len - length);
   
   array->len = length;
   
@@ -222,12 +239,9 @@ g_array_remove_index (GArray* farray,
 	       g_array_elt_pos (array, index + 1),
 	       g_array_elt_len (array, array->len - index - 1));
   
-  array->len -= 1;
+  g_array_shrink (array, 1);
 
-  if (G_UNLIKELY (g_mem_gc_friendly))
-    g_array_elt_zero (array, array->len, 1);
-  else
-    g_array_zero_terminate (array);
+  g_array_zero_terminate (array);
 
   return farray;
 }
@@ -247,12 +261,9 @@ g_array_remove_index_fast (GArray* farra
 	    g_array_elt_pos (array, array->len - 1),
 	    g_array_elt_len (array, 1));
   
-  array->len -= 1;
+  g_array_shrink (array, 1);
 
-  if (G_UNLIKELY (g_mem_gc_friendly))
-    g_array_elt_zero (array, array->len, 1);
-  else
-    g_array_zero_terminate (array);
+  g_array_zero_terminate (array);
 
   return farray;
 }
@@ -273,11 +284,9 @@ g_array_remove_range (GArray       *farr
                g_array_elt_pos (array, index_ + length), 
                (array->len - (index_ + length)) * array->elt_size);
 
-  array->len -= length;
-  if (G_UNLIKELY (g_mem_gc_friendly))
-    g_array_elt_zero (array, array->len, length);
-  else
-    g_array_zero_terminate (array);
+  g_array_shrink (array, length);
+
+  g_array_zero_terminate (array);
 
   return farray;
 }
@@ -325,24 +334,64 @@ g_nearest_pow (gint num)
 }
 
 static void
-g_array_maybe_expand (GRealArray *array,
-		      gint        len)
+g_array_expand_prepare (GRealArray *array,
+		        gint        len)
 {
-  guint want_alloc = g_array_elt_len (array, array->len + len + 
-				      array->zero_terminated);
+  guint curr_len = g_array_elt_len (array, array->len +
+				    array->zero_terminated);
+  guint want_len = g_array_elt_len (array, array->len + len + 
+				    array->zero_terminated);
 
-  if (want_alloc > array->alloc)
+  if (want_len > array->alloc)
     {
-      want_alloc = g_nearest_pow (want_alloc);
+      guint curr_alloc = array->alloc;
+      guint want_alloc = g_nearest_pow (want_len);
+
       want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE);
 
       array->data = g_realloc (array->data, want_alloc);
+      array->alloc = want_alloc;
 
       if (G_UNLIKELY (g_mem_gc_friendly))
-        memset (array->data + array->alloc, 0, want_alloc - array->alloc);
+        memset (array->data + curr_alloc, 0, want_alloc - curr_alloc);
+
+      if (G_UNLIKELY (g_mem_checker_running))
+	VALGRIND_MAKE_NOACCESS(array->data + want_len, want_alloc - want_len);
+    }
+
+  if (G_UNLIKELY (g_mem_checker_running))
+    VALGRIND_MAKE_WRITABLE(array->data + curr_len, want_len - curr_len);
+}
+
+static void
+g_array_shrink (GRealArray *array,
+		      gint        len)
+{
+  guint curr_len = g_array_elt_len (array, array->len +
+				    array->zero_terminated);
+  guint want_len = g_array_elt_len (array, array->len - len + 
+				    array->zero_terminated);
+
+  if (G_UNLIKELY (g_mem_gc_friendly))
+    memset (array->data + want_len, 0, curr_len - want_len);
+
+  if (G_UNLIKELY (g_mem_checker_running))
+    VALGRIND_MAKE_NOACCESS(array->data + want_len, curr_len - want_len);
+
+  if (want_len <= array->alloc >> 2)
+    {
+      guint want_alloc = array->alloc >> 1;
 
+      want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE);
+
+      array->data = g_realloc (array->data, want_alloc);
       array->alloc = want_alloc;
+
+      if (G_UNLIKELY (g_mem_checker_running))
+	VALGRIND_MAKE_NOACCESS(array->data + want_len, want_alloc - want_len);
     }
+
+  array->len -= len;
 }
 
 /* Pointer Array
@@ -357,8 +406,10 @@ struct _GRealPtrArray
   guint     alloc;
 };
 
-static void g_ptr_array_maybe_expand (GRealPtrArray *array,
-				      gint           len);
+static void g_ptr_array_expand_prepare (GRealPtrArray *array,
+					gint           len);
+static void g_ptr_array_shrink (GRealPtrArray *array,
+				gint           len);
 
 GPtrArray*
 g_ptr_array_new (void)
@@ -376,7 +427,21 @@ g_ptr_array_sized_new (guint reserved_si
   array->alloc = 0;
 
   if (reserved_size != 0)
-    g_ptr_array_maybe_expand (array, reserved_size);
+    {
+      guint want_alloc;
+
+      want_alloc = g_nearest_pow (reserved_size);
+      want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE / sizeof (gpointer));
+
+      array->pdata = g_malloc (want_alloc * sizeof (gpointer));
+      array->alloc = want_alloc;
+
+      if (G_UNLIKELY (g_mem_gc_friendly))
+        memset (array->pdata, 0, want_alloc * sizeof (gpointer));
+
+      if (G_UNLIKELY (g_mem_checker_running))
+	VALGRIND_MAKE_NOACCESS(array->pdata, want_alloc * sizeof (gpointer));
+    }
 
   return (GPtrArray*) array;  
 }
@@ -403,24 +468,65 @@ g_ptr_array_free (GPtrArray   *array,
 }
 
 static void
-g_ptr_array_maybe_expand (GRealPtrArray *array,
-			  gint        len)
+g_ptr_array_expand_prepare (GRealPtrArray *array,
+			    gint           len)
 {
-  if ((array->len + len) > array->alloc)
+  guint curr_len = array->len;
+  guint want_len = array->len + len;
+
+  if (want_len > array->alloc)
     {
-      guint old_alloc = array->alloc;
-      array->alloc = g_nearest_pow (array->len + len);
-      array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE);
-      array->pdata = g_realloc (array->pdata, sizeof (gpointer) * array->alloc);
+      guint curr_alloc = array->alloc;
+      guint want_alloc;
+      
+      want_alloc = g_nearest_pow (want_len);
+      want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE / sizeof (gpointer));
+
+      array->pdata = g_realloc (array->pdata, want_alloc * sizeof (gpointer));
+      array->alloc = want_alloc;
+
       if (G_UNLIKELY (g_mem_gc_friendly))
-        for ( ; old_alloc < array->alloc; old_alloc++)
-          array->pdata [old_alloc] = NULL;
+        memset (array->pdata + curr_alloc, 0, (want_alloc - curr_alloc) * sizeof (gpointer));
+
+      if (G_UNLIKELY (g_mem_checker_running))
+	VALGRIND_MAKE_NOACCESS(array->pdata + want_len, (want_alloc - want_len) * sizeof (gpointer));
     }
+  if (G_UNLIKELY (g_mem_checker_running))
+    VALGRIND_MAKE_WRITABLE(array->pdata + curr_len, (want_len - curr_len) * sizeof (gpointer));
+}
+
+static void
+g_ptr_array_shrink (GRealPtrArray *array,
+		    gint           len)
+{
+  guint curr_len = array->len;
+  guint want_len = array->len - len;
+
+  if (G_UNLIKELY (g_mem_gc_friendly))
+    memset (array->pdata + want_len, 0, (curr_len - want_len) * sizeof (gpointer));
+
+  if (G_UNLIKELY (g_mem_checker_running))
+    VALGRIND_MAKE_NOACCESS(array->pdata + want_len, (curr_len - want_len) * sizeof (gpointer));
+
+  if (want_len <= array->alloc >> 2)
+    {
+      guint want_alloc = array->alloc >> 1;
+
+      want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE / sizeof (gpointer));
+
+      array->pdata = g_realloc (array->pdata, want_alloc * sizeof (gpointer));
+      array->alloc = want_alloc;
+
+      if (G_UNLIKELY (g_mem_checker_running))
+	VALGRIND_MAKE_NOACCESS(array->pdata + want_len, (want_alloc - want_len) * sizeof (gpointer));
+    }
+
+  array->len -= len;
 }
 
 void
 g_ptr_array_set_size  (GPtrArray   *farray,
-		       gint	     length)
+		       gint	    length)
 {
   GRealPtrArray* array = (GRealPtrArray*) farray;
 
@@ -428,23 +534,11 @@ g_ptr_array_set_size  (GPtrArray   *farr
 
   if (length > array->len)
     {
-      int i;
-      g_ptr_array_maybe_expand (array, (length - array->len));
-      /* This is not 
-       *     memset (array->pdata + array->len, 0,
-       *            sizeof (gpointer) * (length - array->len));
-       * to make it really portable. Remember (void*)NULL needn't be
-       * bitwise zero. It of course is silly not to use memset (..,0,..).
-       */
-      for (i = array->len; i < length; i++)
-	array->pdata[i] = NULL;
-    }
-  if (G_UNLIKELY (g_mem_gc_friendly) && length < array->len)
-    {
-      int i;
-      for (i = length; i < array->len; i++)
-	array->pdata[i] = NULL;
+      g_ptr_array_expand_prepare (array, (length - array->len));
+      memset (array->pdata + array->len, 0, (length - array->len) * sizeof (gpointer));
     }
+  else if (length < array->len)
+    g_ptr_array_shrink (array, (array->len - length));
 
   array->len = length;
 }
@@ -466,10 +560,7 @@ g_ptr_array_remove_index (GPtrArray* far
     g_memmove (array->pdata + index, array->pdata + index + 1, 
 	       sizeof (gpointer) * (array->len - index - 1));
   
-  array->len -= 1;
-
-  if (G_UNLIKELY (g_mem_gc_friendly))
-    array->pdata[array->len] = NULL;
+  g_ptr_array_shrink (array, 1);
 
   return result;
 }
@@ -490,10 +581,7 @@ g_ptr_array_remove_index_fast (GPtrArray
   if (index != array->len - 1)
     array->pdata[index] = array->pdata[array->len - 1];
 
-  array->len -= 1;
-
-  if (G_UNLIKELY (g_mem_gc_friendly))
-    array->pdata[array->len] = NULL;
+  g_ptr_array_shrink (array, 1);
 
   return result;
 }
@@ -514,13 +602,7 @@ g_ptr_array_remove_range (GPtrArray* far
                &array->pdata[index_ + length], 
                (array->len - (index_ + length)) * sizeof (gpointer));
 
-  array->len -= length;
-  if (G_UNLIKELY (g_mem_gc_friendly))
-    {
-      guint i;
-      for (i = 0; i < length; i++)
-        array->pdata[array->len + i] = NULL;
-    }
+  g_ptr_array_shrink (array, length);
 }
 
 gboolean
@@ -573,7 +655,7 @@ g_ptr_array_add (GPtrArray* farray,
 
   g_return_if_fail (array);
 
-  g_ptr_array_maybe_expand (array, 1);
+  g_ptr_array_expand_prepare (array, 1);
 
   array->pdata[array->len++] = data;
 }
Index: glib/gmem.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gmem.c,v
retrieving revision 1.57
diff -u -p -d -r1.57 gmem.c
--- glib/gmem.c	10 May 2006 00:44:49 -0000	1.57
+++ glib/gmem.c	17 May 2006 06:34:35 -0000
@@ -38,6 +38,8 @@
 #include "gthreadprivate.h"
 #include "galias.h"
 
+#include "contrib/valgrind.h"
+
 #define MEM_PROFILE_TABLE_SIZE 4096
 
 
@@ -684,13 +686,24 @@ gboolean g_mem_gc_friendly = TRUE;
 gboolean g_mem_gc_friendly = FALSE;
 #endif
 
+gboolean g_mem_checker_running = FALSE;
+
 static void
 g_mem_init_nomessage (void)
 {
   gchar buffer[1024];
   const gchar *val;
+  enum {
+    gc_friendly        = 0x01,
+    no_gc_friendly     = 0x02,
+    checker_running    = 0x04,
+    no_checker_running = 0x08
+  };
   static const GDebugKey keys[] = {
-    { "gc-friendly", 1 },
+    { "gc-friendly",        gc_friendly },
+    { "no-gc-friendly",     no_gc_friendly },
+    { "checker-running",    checker_running },
+    { "no-checker-running", no_checker_running }
   };
   gint flags;
   if (g_mem_initialized)
@@ -698,10 +711,21 @@ g_mem_init_nomessage (void)
   /* don't use g_malloc/g_message here */
   val = _g_getenv_nomalloc ("G_DEBUG", buffer);
   flags = !val ? 0 : g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
-  if (flags & 1)        /* gc-friendly */
-    {
-      g_mem_gc_friendly = TRUE;
-    }
+
+  if (G_UNLIKELY (flags & no_gc_friendly))
+    g_mem_gc_friendly = FALSE;
+  else if (G_UNLIKELY (flags & gc_friendly))
+    g_mem_gc_friendly = TRUE;
+
+  /* Add checks for other memory checkers here */
+  if (G_UNLIKELY (RUNNING_ON_VALGRIND))
+    g_mem_checker_running = TRUE;
+
+  if (G_UNLIKELY (flags & no_checker_running))
+    g_mem_checker_running = FALSE;
+  else if (G_UNLIKELY (flags & checker_running))
+    g_mem_checker_running = TRUE;
+
   g_mem_initialized = TRUE;
 }
 
Index: glib/gmem.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gmem.h,v
retrieving revision 1.18
diff -u -p -d -r1.18 gmem.h
--- glib/gmem.h	25 Jan 2006 15:51:43 -0000	1.18
+++ glib/gmem.h	17 May 2006 06:34:35 -0000
@@ -93,6 +93,7 @@ void	 g_mem_set_vtable (GMemVTable	*vtab
 gboolean g_mem_is_system_malloc (void);
 
 GLIB_VAR gboolean g_mem_gc_friendly;
+GLIB_VAR gboolean g_mem_checker_running;
 
 /* Memory profiler and checker, has to be enabled via g_mem_set_vtable()
  */
Index: glib/gslice.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gslice.c,v
retrieving revision 1.19
diff -u -p -d -r1.19 gslice.c
--- glib/gslice.c	10 May 2006 00:44:49 -0000	1.19
+++ glib/gslice.c	17 May 2006 06:34:35 -0000
@@ -42,6 +42,9 @@
 #include <process.h>
 #endif
 
+#include "contrib/valgrind.h"
+#include "contrib/memcheck.h"
+
 
 /* the GSlice allocator is split up into 4 layers, roughly modelled after the slab
  * allocator and magazine extensions as outlined in:
@@ -126,6 +129,56 @@
 static void mem_error (const char *format, ...) G_GNUC_PRINTF (1,2);
 #define mem_assert(cond)    do { if (G_LIKELY (cond)) ; else mem_error ("assertion failed: %s", #cond); } while (0)
 
+/* helpers for valgrind hints */
+#define _G_SLICE_IF_CHECKER(_code)	\
+	G_STMT_START { if (G_UNLIKELY (g_mem_checker_running)) { _code } } G_STMT_END
+
+/* quick wrappers */
+#define _G_SLICE_VALGRIND_MAKE_NOACCESS(_mem, _mem_size) _G_SLICE_IF_CHECKER ( \
+		 VALGRIND_MAKE_NOACCESS(_mem, _mem_size);)
+#define _G_SLICE_VALGRIND_MAKE_WRITABLE(_mem, _mem_size) _G_SLICE_IF_CHECKER ( \
+		 VALGRIND_MAKE_WRITABLE(_mem, _mem_size);)
+#define _G_SLICE_VALGRIND_MAKE_READABLE(_mem, _mem_size) _G_SLICE_IF_CHECKER ( \
+		 VALGRIND_MAKE_READABLE(_mem, _mem_size);)
+
+/* ChunkLink handling */
+#define _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_WRITABLE(_mem) \
+ 	_G_SLICE_VALGRIND_MAKE_WRITABLE (_mem, sizeof (ChunkLink))
+#define _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_READABLE(_mem) \
+ 	_G_SLICE_VALGRIND_MAKE_READABLE (_mem, sizeof (ChunkLink))
+
+/* malloc/free-like operations*/
+/* valgrind only supports redzones before memory allocations, so we cannot
+ * mark the leftover at the end of chunks as redzone easily.  if we don't mark
+ * it as redzone, it still catches errors, as we make the entire block
+ * unaccessible.  but having redzones allocated here has the beauty that the
+ * errors will have the backtrace for this slice allocation.
+ *
+ * what we do is that we make an allocation without redzone followed (in
+ * address space) by another one that consists of only redzone area (possibly
+ * leaving a single byte at the end unused.)
+ */
+
+#define _G_SLICE_VALGRIND_MALLOCLIKE_BLOCK(_mem, _mem_size, _chunk_size, _zeroed) _G_SLICE_IF_CHECKER ( \
+	  if (G_LIKELY (_mem)) \
+	    { \
+		VALGRIND_MALLOCLIKE_BLOCK(_mem, _mem_size, 0, _zeroed); \
+		if ((_mem_size) + 2 <= (_chunk_size)) \
+		  VALGRIND_MALLOCLIKE_BLOCK( \
+			(guint8*)(_mem) + (_mem_size) + (((_chunk_size) - (_mem_size)) >> 1), \
+			0 /* allocation size */, \
+			(((_chunk_size) - (_mem_size)) >> 1), \
+			0 /* zeroed */); \
+	    } \
+	)
+#define _G_SLICE_VALGRIND_FREELIKE_BLOCK(_mem, _mem_size, _chunk_size) _G_SLICE_IF_CHECKER ( \
+		VALGRIND_FREELIKE_BLOCK(_mem, 0); \
+		if ((_mem_size) + 1 < (_chunk_size)) \
+		  VALGRIND_FREELIKE_BLOCK( \
+			(guint8*)(_mem) + (_mem_size) + (((_chunk_size) - (_mem_size)) >> 1), \
+			(((_chunk_size) - (_mem_size)) >> 1)); \
+	)
+
 /* --- structures --- */
 typedef struct _ChunkLink      ChunkLink;
 typedef struct _SlabInfo       SlabInfo;
@@ -529,7 +582,7 @@ magazine_cache_trim (Allocator *allocato
   /* trim magazine cache from tail */
   ChunkLink *current = magazine_chain_prev (allocator->magazines[ix]);
   ChunkLink *trash = NULL;
-  while (ABS (stamp - magazine_chain_uint_stamp (current)) >= allocator->config.working_set_msecs)
+  while (ABS ((gint)stamp - (gint)magazine_chain_uint_stamp (current)) >= allocator->config.working_set_msecs)
     {
       /* unlink */
       ChunkLink *prev = magazine_chain_prev (current);
@@ -733,6 +786,7 @@ thread_memory_magazine1_alloc (ThreadMem
   return chunk;
 }
 
+#include <stdio.h>
 static inline void
 thread_memory_magazine2_free (ThreadMemory *tmem,
                               guint         ix,
@@ -747,8 +801,8 @@ thread_memory_magazine2_free (ThreadMemo
 }
 
 /* --- API functions --- */
-gpointer
-g_slice_alloc (gsize mem_size)
+static gpointer
+_g_slice_allocate (gsize mem_size, int zeroed)
 {
   gsize chunk_size;
   gpointer mem;
@@ -766,25 +820,36 @@ g_slice_alloc (gsize mem_size)
             thread_memory_magazine1_reload (tmem, ix);
         }
       mem = thread_memory_magazine1_alloc (tmem, ix);
+      _G_SLICE_VALGRIND_MALLOCLIKE_BLOCK (mem, mem_size, chunk_size, zeroed);
     }
   else if (acat == 2)           /* allocate through slab allocator */
     {
       g_mutex_lock (allocator->slab_mutex);
       mem = slab_allocator_alloc_chunk (chunk_size);
       g_mutex_unlock (allocator->slab_mutex);
+      _G_SLICE_VALGRIND_MALLOCLIKE_BLOCK (mem, mem_size, chunk_size, zeroed);
     }
   else                          /* delegate to system malloc */
     mem = g_malloc (mem_size);
+
+  if (G_LIKELY (mem)) {
+    if (zeroed)
+      memset (mem, 0, mem_size);
+  }
+
   return mem;
 }
 
 gpointer
+g_slice_alloc (gsize mem_size)
+{
+  return _g_slice_allocate (mem_size, 0);
+}
+
+gpointer
 g_slice_alloc0 (gsize mem_size)
 {
-  gpointer mem = g_slice_alloc (mem_size);
-  if (mem)
-    memset (mem, 0, mem_size);
-  return mem;
+  return _g_slice_allocate (mem_size, 1);
 }
 
 void
@@ -807,15 +872,21 @@ g_slice_free1 (gsize    mem_size,
         }
       if (G_UNLIKELY (g_mem_gc_friendly))
         memset (mem_block, 0, chunk_size);
+      _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_WRITABLE (mem_block);
       thread_memory_magazine2_free (tmem, ix, mem_block);
+      _G_SLICE_VALGRIND_FREELIKE_BLOCK (mem_block, mem_size, chunk_size);
+      _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_READABLE (mem_block);
     }
   else if (acat == 2)                   /* allocate through slab allocator */
     {
       if (G_UNLIKELY (g_mem_gc_friendly))
         memset (mem_block, 0, chunk_size);
+      _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_WRITABLE (mem_block);
       g_mutex_lock (allocator->slab_mutex);
       slab_allocator_free_chunk (chunk_size, mem_block);
       g_mutex_unlock (allocator->slab_mutex);
+      _G_SLICE_VALGRIND_FREELIKE_BLOCK (mem_block, mem_size, chunk_size);
+      _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_READABLE (mem_block);
     }
   else                                  /* delegate to system malloc */
     {
@@ -830,6 +901,7 @@ g_slice_free_chain_with_offset (gsize   
                                 gpointer mem_chain,
                                 gsize    next_offset)
 {
+  /* TODO */
   gpointer slice = mem_chain;
   /* while the thread magazines and the magazine cache are implemented so that
    * they can easily be extended to allow for free lists containing more free
@@ -854,8 +926,8 @@ g_slice_free_chain_with_offset (gsize   
       guint ix = SLAB_INDEX (allocator, chunk_size);
       while (slice)
         {
-          guint8 *current = slice;
-          slice = *(gpointer*) (current + next_offset);
+          guint8 *mem_block = slice;
+          slice = *(gpointer*) (mem_block + next_offset);
           if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
             {
               thread_memory_swap_magazines (tmem, ix);
@@ -863,8 +935,11 @@ g_slice_free_chain_with_offset (gsize   
                 thread_memory_magazine2_unload (tmem, ix);
             }
           if (G_UNLIKELY (g_mem_gc_friendly))
-            memset (current, 0, chunk_size);
-          thread_memory_magazine2_free (tmem, ix, current);
+            memset (mem_block, 0, chunk_size);
+	  _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_WRITABLE (mem_block);
+	  thread_memory_magazine2_free (tmem, ix, mem_block);
+	  _G_SLICE_VALGRIND_FREELIKE_BLOCK (mem_block, mem_size, chunk_size);
+	  _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_READABLE (mem_block);
         }
     }
   else if (acat == 2)                   /* allocate through slab allocator */
@@ -872,22 +947,25 @@ g_slice_free_chain_with_offset (gsize   
       g_mutex_lock (allocator->slab_mutex);
       while (slice)
         {
-          guint8 *current = slice;
-          slice = *(gpointer*) (current + next_offset);
-          if (G_UNLIKELY (g_mem_gc_friendly))
-            memset (current, 0, chunk_size);
-          slab_allocator_free_chunk (chunk_size, current);
+          guint8 *mem_block = slice;
+          slice = *(gpointer*) (mem_block + next_offset);
+	  if (G_UNLIKELY (g_mem_gc_friendly))
+	    memset (mem_block, 0, chunk_size);
+	  _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_WRITABLE (mem_block);
+	  slab_allocator_free_chunk (chunk_size, mem_block);
+	  _G_SLICE_VALGRIND_FREELIKE_BLOCK (mem_block, mem_size, chunk_size);
+	  _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_READABLE (mem_block);
         }
       g_mutex_unlock (allocator->slab_mutex);
     }
   else                                  /* delegate to system malloc */
     while (slice)
       {
-        guint8 *current = slice;
-        slice = *(gpointer*) (current + next_offset);
+        guint8 *mem_block = slice;
+        slice = *(gpointer*) (mem_block + next_offset);
         if (G_UNLIKELY (g_mem_gc_friendly))
-          memset (current, 0, mem_size);
-        g_free (current);
+          memset (mem_block, 0, mem_size);
+        g_free (mem_block);
       }
 }
 
@@ -950,25 +1028,28 @@ allocator_add_slab (Allocator *allocator
   /* assert alignment */
   mem_assert (aligned_memory == (gpointer) addr);
   /* basic slab info setup */
-  sinfo = (SlabInfo*) (mem + page_size - SLAB_INFO_SIZE);
+  sinfo = (SlabInfo*) (mem);
+  _G_SLICE_VALGRIND_MAKE_WRITABLE (sinfo, sizeof (SlabInfo));
   sinfo->n_allocated = 0;
   sinfo->chunks = NULL;
   /* figure cache colorization */
-  n_chunks = ((guint8*) sinfo - mem) / chunk_size;
-  padding = ((guint8*) sinfo - mem) - n_chunks * chunk_size;
+  n_chunks = (page_size - SLAB_INFO_SIZE) / chunk_size;
+  padding = (page_size - SLAB_INFO_SIZE) - n_chunks * chunk_size;
   if (padding)
     {
       color = (allocator->color_accu * P2ALIGNMENT) % padding;
       allocator->color_accu += allocator->config.color_increment;
     }
   /* add chunks to free list */
-  chunk = (ChunkLink*) (mem + color);
+  chunk = (ChunkLink*) (mem + P2ALIGN (sizeof (SlabInfo)) + color);
   sinfo->chunks = chunk;
   for (i = 0; i < n_chunks - 1; i++)
     {
+      _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_WRITABLE (chunk);
       chunk->next = (ChunkLink*) ((guint8*) chunk + chunk_size);
       chunk = chunk->next;
     }
+  _G_SLICE_VALGRIND_MAKE_CHUNK_LINK_WRITABLE (chunk);
   chunk->next = NULL;   /* last chunk */
   /* add slab to slab ring */
   allocator_slab_stack_push (allocator, ix, sinfo);
@@ -1003,7 +1084,7 @@ slab_allocator_free_chunk (gsize    chun
   gsize addr = ((gsize) mem / page_size) * page_size;
   /* mask page adress */
   guint8 *page = (guint8*) addr;
-  SlabInfo *sinfo = (SlabInfo*) (page + page_size - SLAB_INFO_SIZE);
+  SlabInfo *sinfo = (SlabInfo*) page;
   /* assert valid chunk count */
   mem_assert (sinfo->n_allocated > 0);
   /* add chunk to free list */
@@ -1092,8 +1173,10 @@ allocator_memalign (gsize alignment,
     }
   aligned_memory = g_trash_stack_pop (&compat_valloc_trash);
 #endif
-  if (!aligned_memory)
+  if (G_UNLIKELY (!aligned_memory))
     errno = err;
+  else
+    _G_SLICE_VALGRIND_MAKE_NOACCESS(aligned_memory, memsize);
   return aligned_memory;
 }
 
Index: glib/gutils.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gutils.c,v
retrieving revision 1.191
diff -u -p -d -r1.191 gutils.c
--- glib/gutils.c	10 May 2006 00:44:49 -0000	1.191
+++ glib/gutils.c	17 May 2006 06:34:35 -0000
@@ -38,6 +38,7 @@
 #include <stdio.h>
 #include <locale.h>
 #include <string.h>
+#include <ctype.h>		/* For tolower() */
 #include <errno.h>
 #ifdef HAVE_PWD_H
 #include <pwd.h>
@@ -552,16 +553,33 @@ g_find_program_in_path (const gchar *pro
   return NULL;
 }
 
+static gboolean
+debug_key_matches (const gchar *key,
+		   const gchar *token,
+		   guint        length)
+{
+  for (; length; length--, key++, token++)
+    {
+      char k = (*key   == '_') ? '-' : tolower (*key  );
+      char t = (*token == '_') ? '-' : tolower (*token);
+
+      if (k != t)
+        return FALSE;
+    }
+
+  return *key == '\0';
+}
+
 /**
  * g_parse_debug_string:
- * @string: a list of debug options separated by ':' or "all" 
- *     to set all flags.
+ * @string: a list of debug options separated by colons, spaces, or
+ * commas; or the string "all" to set all flags.
  * @keys: pointer to an array of #GDebugKey which associate 
  *     strings with bit flags.
  * @nkeys: the number of #GDebugKey<!-- -->s in the array.
  *
- * Parses a string containing debugging options separated 
- * by ':' into a %guint containing bit flags. This is used 
+ * Parses a string containing debugging options
+ * into a %guint containing bit flags. This is used 
  * within GDK and GTK+ to parse the debug options passed on the
  * command line or through environment variables.
  *
@@ -594,17 +612,16 @@ g_parse_debug_string  (const gchar     *
       
       while (*p)
 	{
-	  q = strchr (p, ':');
+	  q = strpbrk (p, ":, ");
 	  if (!q)
 	    q = p + strlen(p);
 	  
 	  for (i = 0; i < nkeys; i++)
-	    if (g_ascii_strncasecmp (keys[i].key, p, q - p) == 0 &&
-		keys[i].key[q - p] == '\0')
+	    if (debug_key_matches (keys[i].key, p, q - p))
 	      result |= keys[i].value;
 	  
 	  p = q;
-	  if (*p == ':')
+	  if (*p)
 	    p++;
 	}
     }
Index: tests/array-test.c
===================================================================
RCS file: /cvs/gnome/glib/tests/array-test.c,v
retrieving revision 1.6
diff -u -p -d -r1.6 array-test.c
--- tests/array-test.c	14 Mar 2005 06:01:51 -0000	1.6
+++ tests/array-test.c	17 May 2006 06:34:36 -0000
@@ -83,6 +83,23 @@ main (int   argc,
   g_ptr_array_foreach (gparray, sum_up, &sum);
   g_assert (sum == 49995000);
 
+  g_ptr_array_remove (gparray, GINT_TO_POINTER (13));
+
+  sum = 0;
+  g_ptr_array_foreach (gparray, sum_up, &sum);
+  g_assert (sum == 49995000 - 13);
+
+  g_ptr_array_index (gparray, 9998)++;
+
+  g_ptr_array_foreach (gparray, sum_up, &sum);
+  g_assert (sum == (49995000 - 13) * 2 + 1);
+
+  /*
+   * uncommenting the following line should make
+   * valgrind err about invalid access.
+   */
+  /* g_ptr_array_index (gparray, 9999)++; */
+
   g_ptr_array_free (gparray, TRUE);
 
   /* byte arrays */
Index: tests/slice-test.c
===================================================================
RCS file: /cvs/gnome/glib/tests/slice-test.c,v
retrieving revision 1.6
diff -u -p -d -r1.6 slice-test.c
--- tests/slice-test.c	5 Apr 2006 05:56:47 -0000	1.6
+++ tests/slice-test.c	17 May 2006 06:34:36 -0000
@@ -26,7 +26,7 @@
 static guint    prime_size = 1021; // 769; // 509
 static gboolean clean_memchunks = FALSE;
 static guint    number_of_blocks = 10000;          /* total number of blocks allocated */
-static guint    number_of_repetitions = 10000;     /* number of alloc+free repetitions */
+static guint    number_of_repetitions = 1000;     /* number of alloc+free repetitions */
 
 /* --- old memchunk prototypes (memchunks.c) --- */
 void            old_mem_chunks_init     (void);
@@ -135,7 +135,12 @@ test_memchunk_thread (gpointer data)
 static gpointer
 test_sliced_mem_thread (gpointer data)
 {
+  guint i, j;
+  guint8 **ps;
+  guint   *ss;
+
   guint32 rand_accu = 2147483563;
+
   /* initialize random numbers */
   if (data)
     rand_accu = *(guint32*) data;
@@ -146,9 +151,8 @@ test_sliced_mem_thread (gpointer data)
       rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16);
     }
 
-  guint i, j;
-  guint8 **ps = g_new (guint8*, number_of_blocks);
-  guint   *ss = g_new (guint, number_of_blocks);
+  ps = g_new (guint8*, number_of_blocks);
+  ss = g_new (guint, number_of_blocks);
   /* create number_of_blocks random sizes */
   for (i = 0; i < number_of_blocks; i++)
     ss[i] = quick_rand32() % prime_size;
@@ -169,7 +173,16 @@ test_sliced_mem_thread (gpointer data)
     }
   /* free number_of_blocks blocks */
   for (i = 0; i < number_of_blocks; i++)
-    g_slice_free1 (ss[i], ps[i]);
+    {
+      g_slice_free1 (ss[i], ps[i]);
+      /*
+       * uncomment the following lines to get
+       * valgrind issue an error if glib valgrind
+       * hints are enabled.
+       */
+      if (i == 0)
+        ps[i][0]++;
+    }
   /* alloc and free many equally sized chunks in a row */
   for (i = 0; i < number_of_repetitions; i++)
     {
@@ -189,7 +202,7 @@ test_sliced_mem_thread (gpointer data)
 static void
 usage (void)
 {
-  g_print ("Usage: slice-test [n_threads] [G|S|M|O][f][c] [maxblocksize] [seed]\n");
+  g_print ("Usage: slice-test [n_threads] [G|S|M|O][f][c] [repetitions] [maxblocksize] [seed]\n");
 }
 
 int
@@ -197,8 +210,11 @@ main (int   argc,
       char *argv[])
 {
   guint seed32, *seedp = NULL;
+  gchar strseed[64] = "<random>";
   gboolean ccounters = FALSE, use_memchunks = FALSE;
   guint n_threads = 1;
+  GThread **threads;
+  guint i;
   const gchar *mode = "slab allocator + magazine cache", *emode = " ";
   if (argc > 1)
     n_threads = g_ascii_strtoull (argv[1], NULL, 10);
@@ -240,10 +256,12 @@ main (int   argc,
           }
     }
   if (argc > 3)
-    prime_size = g_ascii_strtoull (argv[3], NULL, 10);
+    number_of_repetitions = g_ascii_strtoull (argv[3], NULL, 10);
   if (argc > 4)
+    prime_size = g_ascii_strtoull (argv[4], NULL, 10);
+  if (argc > 5)
     {
-      seed32 = g_ascii_strtoull (argv[4], NULL, 10);
+      seed32 = g_ascii_strtoull (argv[5], NULL, 10);
       seedp = &seed32;
     }
 
@@ -252,13 +270,11 @@ main (int   argc,
   if (argc <= 1)
     usage();
 
-  gchar strseed[64] = "<random>";
   if (seedp)
     g_snprintf (strseed, 64, "%u", *seedp);
-  g_print ("Starting %d threads allocating random blocks <= %u bytes with seed=%s using %s%s\n", n_threads, prime_size, strseed, mode, emode);
+  g_print ("Starting %d threads allocating random blocks <= %u bytes %u times, with seed=%s using %s%s\n", n_threads, prime_size, number_of_repetitions, strseed, mode, emode);
   
-  GThread *threads[n_threads];
-  guint i;
+  threads = g_new (GThread *, n_threads);
   if (!use_memchunks)
     for (i = 0; i < n_threads; i++)
       threads[i] = g_thread_create_full (test_sliced_mem_thread, seedp, 0, TRUE, FALSE, 0, NULL);
@@ -270,6 +286,7 @@ main (int   argc,
     }
   for (i = 0; i < n_threads; i++)
     g_thread_join (threads[i]);
+  g_free (threads);
   
   if (ccounters)
     {
