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 643624 - Can g_variant_unref() on an already free'd variant
Can g_variant_unref() on an already free'd variant
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: gdbus
2.27.x
Other Linux
: Normal normal
: ---
Assigned To: David Zeuthen (not reading bugmail)
gtkdev
Depends on:
Blocks:
 
 
Reported: 2011-03-01 22:11 UTC by Ted Gould
Modified: 2011-04-27 03:23 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Adds a sink before the signal gets emitted. (486 bytes, patch)
2011-03-01 22:13 UTC, Ted Gould
none Details | Review
Make sure signals with VARIANT params always collect their arguments (4.22 KB, patch)
2011-03-02 14:49 UTC, Christian Persch
none Details | Review
Add G_SIGNAL_MUST_COLLECT (6.27 KB, patch)
2011-03-04 17:23 UTC, Christian Persch
needs-work Details | Review
Use G_SIGNAL_MUST_COLLECT for VARIANT signals (4.24 KB, patch)
2011-03-04 17:24 UTC, Christian Persch
committed Details | Review
my changes to the patch (5.85 KB, patch)
2011-03-04 18:48 UTC, Allison Karlitskaya (desrt)
committed Details | Review

Description Ted Gould 2011-03-01 22:11:25 UTC
Because the signal handler will ref and unref the variant it's possible that when doing the unref() the variant has already been free'd. So, in order to combat that we need to ensure that the caller is sinking it first and then unref'ing it.
Comment 1 Ted Gould 2011-03-01 22:13:29 UTC
Created attachment 182217 [details] [review]
Adds a sink before the signal gets emitted.
Comment 2 Christian Persch 2011-03-01 23:47:18 UTC
I think instead of adding an extra ref, you can just drop the UNref after the signal emission.
Comment 3 Ted Gould 2011-03-02 02:44:56 UTC
I don't believe so because the marshaller will behave differently depending if someone is registered for the signal or not.
Comment 4 Christian Persch 2011-03-02 13:00:33 UTC
Hmm. Tried a testcase, and you're right. I guess the docs for G_TYPE_VARIANT should mention that somewhere; I certainly didn't know that when I *wrote* that code in bug 610863.
Comment 5 David Zeuthen (not reading bugmail) 2011-03-02 14:01:26 UTC
(In reply to comment #4)
> Hmm. Tried a testcase, and you're right. I guess the docs for G_TYPE_VARIANT
> should mention that somewhere; I certainly didn't know that when I *wrote* that
> code in bug 610863.

Sounds like a bug then. The semantics really need to be that g_signal_emits() consumes the GVariant if it is floating. No matter how many connections there are. Otherwise everything is going to break....
Comment 6 Christian Persch 2011-03-02 14:10:44 UTC
It's because of this check in g_signal_emit_valist, before collecting the varargs:

  /* optimize NOP emissions */
  if (signal_check_skip_emission (node, instance, detail))
    {
      /* nothing to do to emit this signal */
      SIGNAL_UNLOCK ();
      /* g_printerr ("omitting emission of \"%s\"\n", node->name); */
      return;
    }
Comment 7 Christian Persch 2011-03-02 14:49:57 UTC
Created attachment 182259 [details] [review]
Make sure signals with VARIANT params always collect their arguments

Bug #643624.
Comment 8 Ted Gould 2011-03-02 14:52:33 UTC
I would think that this same check should also be done for G_TYPE_OBJECT for the cases of objects that inherit from GInitiallyUnowned.
Comment 9 Christian Persch 2011-03-02 14:55:20 UTC
GInitiallyUnowned is different in that the value collection uses g_object_ref, not ref_sink.
Comment 10 Matthias Clasen 2011-03-04 01:18:33 UTC
Special-casing variant in signal-emission like this seems like a totally broken hack to me.
Comment 11 Allison Karlitskaya (desrt) 2011-03-04 03:11:37 UTC
from an API standpoint: the principle of least surprise dictates that we ought to expect that g_signal_emit() on a floating GVariant consumes the variant and frees it when it's done.

From the standpoint of maintaining compatibility with code we already have, things are a little bit more complicated.  For example, David's existing GDBus code would break since he is doing the unref() after the signal emit.

Only cases where you emit a floating GVariant would be affected, of course, and we could argue that this was merely "ill defined" before...  I'm not sure of the impact on code in the wild, but my gut tells me that it wouldn't be *too* substantial.

In any case, I think it would be worth the pain to get this right.  I'm surprised it wasn't already working...
Comment 12 Allison Karlitskaya (desrt) 2011-03-04 03:35:53 UTC
Christian is right, unfortunately.

If no handlers are connected then the signal emission is skipped, including collecting the varargs from the emit call.

The problem is that we really need to sink that floating variant.

In order to do that, we need to collect the pointer.

In order to do that, we _can't_ skip the emission.

The only other option is to change the definition of what it means to skip an emission to including collecting (and discarding) the argument list.  I don't like this idea for its performance implications in the non-GVariant case.
Comment 13 Allison Karlitskaya (desrt) 2011-03-04 06:01:31 UTC
Matthias suggests a solution here that is somewhat more elegant than scanning the argument type list: add a G_SIGNAL_MUST_COLLECT flag that disables the no-emit optimisation for that signal.

I like that option.

If we don't do it, though, the only thing we can really do is add docs telling people that they can't rely on their pointers being collected, so they better sink the values for themselves.  In that case, Ted's original patch is clearly correct.
Comment 14 Christian Persch 2011-03-04 17:23:22 UTC
Created attachment 182500 [details] [review]
Add G_SIGNAL_MUST_COLLECT

In some cases, signal arguments have to be collected, even if there are i
no signal handlers connected (e.g. for GVariant parameters, where collection
consumes a floating variant).

Bug #643624.
Comment 15 Christian Persch 2011-03-04 17:24:25 UTC
Created attachment 182501 [details] [review]
Use G_SIGNAL_MUST_COLLECT for VARIANT signals

Bug #643624.
Comment 16 Matthias Clasen 2011-03-04 17:30:53 UTC
Review of attachment 182500 [details] [review]:

::: gobject/gsignal.h
@@ +113,2 @@
  * 
  * The signal flags are used to specify a signal's behaviour, the overall

You MUST ALWAYS use the same name :-)
Comment 17 Allison Karlitskaya (desrt) 2011-03-04 18:03:02 UTC
Review of attachment 182500 [details] [review]:

::: gobject/gsignal.c
@@ +1539,3 @@
+   */
+  for (i = 0; i < n_params; ++i)
+    g_return_val_if_fail (param_types[i] != G_TYPE_VARIANT || (signal_flags & G_SIGNAL_MUST_COLLECT), 0);

I disagree with this check.  Not everyone needs the must-collect behaviour with GVariant if they know, for example, that they will never be dealing in floating values.

Think particularly about language bindings that sink everything immediately and don't want to have to worry about this.

@@ +2944,3 @@
   /* optimize NOP emissions */
+  skip_emission = signal_check_skip_emission (node, instance, detail);
+  if (skip_emission && (node->flags & G_SIGNAL_MUST_COLLECT) == 0)

I think this is too complicated.

I'd prefer just having a separate check in the skip_emission() code (or better still -- another check in g_signal_new to avoid setting the offset, thereby preventing skipping from being a possibility).

Consider that the existing code that prevents skipping when a return value needs to be set goes through the full signal emission stuff anyway.  I don't think it's that expensive...

On the balance of it, I actually suspect that your complicating the logic here is a bigger net loss to signal emission (99.99% of which won't be using this flag at all) than is saved by skipping the actual emission.

::: gobject/gsignal.h
@@ +109,3 @@
  *  third-party code.
  * @G_SIGNAL_NO_HOOKS: No emissions hooks are supported for this signal.
+ * @G_SIGNAL_ALWAYS_COLLECT: Varargs signal emission will always collect the

The context of Matthias's comment was slightly off.  He was referring to this. :)
Comment 18 Allison Karlitskaya (desrt) 2011-03-04 18:48:42 UTC
Created attachment 182512 [details] [review]
my changes to the patch

Here's what I had in mind, just to make sure we're all on the same page.

Two things remain: do we backport it?

-and-

We talked on IRC about adding a check that would do the following: when collecting GVariant parameters for signals that do not have the MUST_COLLECT flag and finding one of them floating, emit a very detailed warning message along the lines of:

"
You passed a floating GVariant instance to g_signal_emit() for the "frobbed" signal of the class GtkFooBar.  g_signal_emit() typically consumes floating references, but in the case of a skipped emission (due to no handlers being connected), the reference will not be collected at all.  Consider the use of the  G_SIGNAL_MUST_COLLECT flag to avoid this problem.
"
Comment 19 Matthias Clasen 2011-03-07 04:14:56 UTC
Patch looks good to me. Thanks for adding a testcase.

As for, do we backport it: I think we should

And for the warning: I think it is a good idea
Comment 20 David Zeuthen (not reading bugmail) 2011-04-15 09:57:49 UTC
Looks like we never finished fixing this bug as MUST_COLLECT is not yet used in signals using G_TYPE_VARIANT in gio yet... that's just an oversight, yes?
Comment 21 Christian Persch 2011-04-15 10:52:29 UTC
Yes. Attachment 182501 [details] is a patch for that; looks like it was just forgotten while discussing the main problem...
Comment 22 Allison Karlitskaya (desrt) 2011-04-15 13:25:31 UTC
Note: MUST_COLLECT is not required for all signals with GVariant parameters.  You only need it if you intend to pass floating variants at some point.
Comment 23 David Zeuthen (not reading bugmail) 2011-04-15 13:33:01 UTC
Comment on attachment 182501 [details] [review]
Use G_SIGNAL_MUST_COLLECT for VARIANT signals

Looks good to me - at least for the GDBusProxy parts where this is needed (what the bug was originally about).
Comment 24 Matthias Clasen 2011-04-27 02:57:22 UTC
Review of attachment 182512 [details] [review]:

This was committed a while ago
Comment 25 Matthias Clasen 2011-04-27 03:06:39 UTC
Review of attachment 182501 [details] [review]:

Committed
Comment 26 Matthias Clasen 2011-04-27 03:08:00 UTC
Review of attachment 182501 [details] [review]:

Committed
Comment 27 Matthias Clasen 2011-04-27 03:08:00 UTC
Review of attachment 182501 [details] [review]:

Committed