After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 698595 - the valgrind/priv-before-instance bug
the valgrind/priv-before-instance bug
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: gobject
unspecified
Other All
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2013-04-22 16:51 UTC by Allison Karlitskaya (desrt)
Modified: 2013-04-26 16:00 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Add a copy of valgrind.h to glib/ (282.18 KB, patch)
2013-04-22 16:51 UTC, Allison Karlitskaya (desrt)
committed Details | Review
gslice: disable by default under valgrind (2.02 KB, patch)
2013-04-22 16:51 UTC, Allison Karlitskaya (desrt)
committed Details | Review
gtype: put private data before the instance (12.63 KB, patch)
2013-04-22 16:52 UTC, Allison Karlitskaya (desrt)
committed Details | Review

Description Allison Karlitskaya (desrt) 2013-04-22 16:51:40 UTC
There are lots of reasons to want the private data before the instance.
The two biggest ones:

 - having the priv at a constant offset to the instance pointer means
   that we can stop putting ->priv pointers in our structures and
   instead statically store an integer offset and use it directly

 - it makes it possible to have GProperty without having code to jump
   through ->priv pointers (which would only work in the case that you
   actually have a ->priv pointer to jump through).  This solves the
   main issue that is preventing GProperty from landing.

Relatedly: in order for this priv-before-instance stuff to not cause
Valgrind to become completely useless, we need to add some client
requests to inform Valgrind of what's going on.  We take a copy of
BSD-licenced valgrind.h into glib (not to inflate our build-deps) and
since we have it, use it to address another common Valgrind pain:
disable gslice when running under it.
Comment 1 Allison Karlitskaya (desrt) 2013-04-22 16:51:50 UTC
Created attachment 242153 [details] [review]
Add a copy of valgrind.h to glib/

This is a BSD-licenced header file that is designed to be copy-pasted
into programs.  It will allow us to detect if we are running under
Valgrind and send "client requests" to it.

We will use this for a couple of reasons in upcoming patches.
Comment 2 Allison Karlitskaya (desrt) 2013-04-22 16:51:55 UTC
Created attachment 242154 [details] [review]
gslice: disable by default under valgrind

All experienced GLib hackers know that G_SLICE=always-malloc is
absolutely essential when valgrinding but many users of GLib don't know
about this and get hit pretty hard when valgrinding their programs.

When initialising gslice, add a check to see if we are running under
valgrind and disable ourselves if we are.

We only do the check in the case that G_SLICE= was not specified in the
environment, so setting it to an empty string will prevent this default
behaviour.

I considered modifying gslice to use the VALGRIND_MALLOCLIKE_BLOCK
client request in all cases in order to just mark the blocks properly
but these calls are not free and gslice is pretty hyper-optimised.  It's
easier to just disable gslice completely and this way we only have to do
one check during startup.  It's also theoretically possible that someone
might want to use valgrind to debug gslice, in which case the extra
annotations would probably cause quite a lot of difficulty.
Comment 3 Allison Karlitskaya (desrt) 2013-04-22 16:52:01 UTC
Created attachment 242155 [details] [review]
gtype: put private data before the instance

Classically, a GTypeInstance has had the following layout:

 [[[[GTypeInstance] GObject] TypeA] TypeB] [TypeAPrivate] [TypeBPrivate]

where TypeB is a subclass of TypeA which is a GObject.  Both TypeA and
TypeB use pivate data.

The main problem with this approach is that the offset between a pointer
to an instance of TypeA and the TypeAPrivate is not constant: it changes
depending on the depth of derivation and the size of the instance
structures of the derived types.  For example, changing the size of the
TypeB structure in the above example would push the TypeAPrivate further
along.

This complicates the implementation of g_type_instance_get_private().
In particular, during object construction when the class pointer to the
'complete type' of the object is not yet stored in the header of the
GTypeInstance, we need a lookup table in order to be able to implement
g_type_instance_get_private() accurately.

We can avoid this problem by storing the private data before the
structures, in reverse order, like so:

  [TypeBPrivate] [TypeAPrivate] [[[[GTypeInstance] GObject] TypeA] TypeB]

Now the distance between TypeA and TypeAPrivate depends only on the size
of GObject and GTypeInstance, which are static.  Even in the case of
TypeB, the distance is not statically known but can be determined at
runtime and is constant (because we will know the size of TypeAPrivate
by the time we initialise TypeB and it won't change).

This approach requires a slighty dirty trick: allocating extra memory
_before_ the pointer we return from g_type_create_instance().  The main
problem with this is that it will cause valgrind to behave very badly,
reporting almost everything as "possibly lost".

We can correct for this by including a few valgrind client requests in
order to inform it that the start of the GTypeInstance should be
considered a block of memory and that pointers to it should mean that
this block is reachable.  In order to make the private data reachable,
we also declare it as a block and include an extra pointer from the end
of the primary block pointing back at it.  All of this is only done if
we are running under Valgrind.
Comment 4 Alexander Larsson 2013-04-22 19:43:11 UTC
Review of attachment 242153 [details] [review]:

ack
Comment 5 Alexander Larsson 2013-04-22 19:48:12 UTC
Review of attachment 242154 [details] [review]:

ack
Comment 6 Alexander Larsson 2013-04-22 20:06:06 UTC
Review of attachment 242155 [details] [review]:

looks good otherwise

::: gobject/gtype.c
@@ +24,3 @@
 #include "config.h"
 
+#include <valgrind/valgrind.h>

This does not use the included version.

@@ +1925,3 @@
+      g_slice_free1 (private_size + ivar_size + sizeof (gpointer), allocated);
+
+      VALGRIND_FREELIKE_BLOCK (instance + sizeof (GTypeInstance), 0);

Should just be instance

@@ +4519,3 @@
     }
 
+  return ((gchar *) instance) - node->data->instance.private_size;

Soo beautiful!
Comment 7 Allison Karlitskaya (desrt) 2013-04-22 20:16:41 UTC
Attachment 242153 [details] pushed as c8d56d7 - Add a copy of valgrind.h to glib/
Attachment 242154 [details] pushed as 00fbc2f - gslice: disable by default under valgrind
Attachment 242155 [details] pushed as 31fde56 - gtype: put private data before the instance
Comment 8 Adam Dingle 2013-04-26 15:51:31 UTC
I run Ubuntu 13.04.  I generally install glib built from git master, which is either brave or foolish, depending on your perspective.  :) Recently I updated glib and found a pretty significant regression in my desktop environment: whenever I close a terminal window or most other windows, unity-panel-service crashes.  It restarts automatically, but I see all indicators on the system panel vanish and then reappear.

I bisected glib and found that it broke with the change '31fde56 - gtype: put private data before the
instance' referenced here.  The unity-panel-service stack trace is below.  It looks a bit gnarly and I haven't investigated further.  But I thought you should know about this.

  • #0 g_type_check_instance
    at gtype.c line 4082
  • #1 g_signal_handlers_disconnect_matched
  • #2 gtk_accel_label_set_accel_closure
    at gtkaccellabel.c line 581
  • #3 gtk_accel_label_set_accel_widget
    at gtkaccellabel.c line 517
  • #4 gtk_accel_label_destroy
    at gtkaccellabel.c line 295
  • #5 g_cclosure_marshal_VOID__VOID
    at gmarshal.c line 85
  • #6 g_type_class_meta_marshal
    at gclosure.c line 970
  • #7 g_closure_invoke
    at gclosure.c line 777
  • #8 signal_emit_unlocked_R
    at gsignal.c line 3700
  • #9 g_signal_emit_valist
    at gsignal.c line 3328
  • #10 g_signal_emit
    at gsignal.c line 3384
  • #11 gtk_widget_dispose
    at gtkwidget.c line 11016
  • #12 g_object_run_dispose
    at gobject.c line 1062
  • #13 gtk_container_destroy
    at gtkcontainer.c line 1384
  • #14 g_cclosure_marshal_VOID__VOID
    at gmarshal.c line 85
  • #15 g_type_class_meta_marshal
    at gclosure.c line 970
  • #16 g_closure_invoke
    at gclosure.c line 777
  • #17 signal_emit_unlocked_R
    at gsignal.c line 3700
  • #18 g_signal_emit_valist
    at gsignal.c line 3328
  • #19 g_signal_emit
    at gsignal.c line 3384
  • #20 gtk_widget_dispose
    at gtkwidget.c line 11016
  • #21 g_object_run_dispose
    at gobject.c line 1062
  • #22 ??
    from /usr/lib/x86_64-linux-gnu/libdbusmenu-gtk3.so.4
  • #23 g_datalist_clear
    at gdataset.c line 277
  • #24 g_object_finalize
    at gobject.c line 1019
  • #25 g_object_unref
    at gobject.c line 3177
  • #26 ??
    from /usr/lib/x86_64-linux-gnu/libdbusmenu-glib.so.4
  • #27 g_object_unref
    at gobject.c line 3140
  • #28 ??
    from /usr/lib/x86_64-linux-gnu/libdbusmenu-glib.so.4
  • #29 g_object_unref
    at gobject.c line 3140
  • #30 ??
    from /usr/lib/x86_64-linux-gnu/libdbusmenu-glib.so.4
  • #31 g_object_unref
    at gobject.c line 3140
  • #32 ??
    from /usr/lib/indicators3/7/libappmenu.so
  • #33 g_object_unref
    at gobject.c line 3140
  • #34 ??
    from /usr/lib/indicators3/7/libappmenu.so
  • #35 g_cclosure_marshal_VOID__OBJECTv
    at gmarshal.c line 1312
  • #36 _g_closure_invoke_va
    at gclosure.c line 840
  • #37 g_signal_emit_valist
    at gsignal.c line 3234
  • #38 g_signal_emit
    at gsignal.c line 3384
  • #39 ??
    from /usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2
  • #40 g_closure_invoke
    at gclosure.c line 777
  • #41 signal_emit_unlocked_R
    at gsignal.c line 3584
  • #42 g_signal_emit_valist
    at gsignal.c line 3328
  • #43 g_signal_emit
    at gsignal.c line 3384
  • #44 ??
    from /usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2
  • #45 dbus_connection_dispatch
    from /lib/x86_64-linux-gnu/libdbus-1.so.3
  • #46 ??
    from /usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2
  • #47 g_main_dispatch
    at gmain.c line 3058
  • #48 g_main_context_dispatch
    at gmain.c line 3634
  • #49 g_main_context_iterate
    at gmain.c line 3705
  • #50 g_main_loop_run
    at gmain.c line 3899
  • #51 gtk_main
    at gtkmain.c line 1156
  • #52 main

Comment 9 Adam Dingle 2013-04-26 16:00:57 UTC
By the way I've created a bug for the unity-panel-service crash downstream at https://bugs.launchpad.net/unity/+bug/1173262 .