#1777 Warning on OS X during destruction

Bug
closed-fixed
5
2016-01-18
2015-11-03
Jiri Techet
No

On OS X with GTK backend I get the following warning on destruction:

(geany:70109): GLib-GObject-CRITICAL **: g_object_ref: assertion 'object->ref_count > 0' failed

twice for every closed editor in Geany. I have bisected this issue to commit

6c3f6c0ec9e3a41bfc1f855523e2ccfbadf6ed84

When run in debugger with --g-fatal-warnings, I get the following backtrace:

  • thread #1: tid = 0x3e51ba, 0x0000000100bd9d11 libglib-2.0.0.dylib`g_logv + 433, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
  • frame #0: 0x0000000100bd9d11 libglib-2.0.0.dylibg_logv + 433 frame #1: 0x0000000100bda8d6 libglib-2.0.0.dylibg_log + 134
    frame #2: 0x0000000100b4c73c libgobject-2.0.0.dylibg_object_ref + 204 frame #3: 0x0000000100b4b901 libgobject-2.0.0.dylibg_value_object_collect_value + 49
    frame #4: 0x0000000100b5e7c9 libgobject-2.0.0.dylibg_signal_emit_valist + 2057 frame #5: 0x0000000100b5eeb6 libgobject-2.0.0.dylibg_signal_emit + 134
    frame #6: 0x00000001004c6255 libgtk-quartz-2.0.0.dylibgtk_widget_unparent + 677 frame #7: 0x000000010008750f libgeany.0.dylibScintillaGTK::Destroy(_GObject*) + 31
    frame #8: 0x0000000100b4c938 libgobject-2.0.0.dylibg_object_unref + 440 frame #9: 0x00000001002e6b96 libgtk-quartz-2.0.0.dylibgtk_box_forall + 54
    frame #10: 0x000000010031ab9c libgtk-quartz-2.0.0.dylibgtk_container_destroy + 76 frame #11: 0x0000000100b47432 libgobject-2.0.0.dylibg_closure_invoke + 290
    frame #12: 0x0000000100b5dee1 libgobject-2.0.0.dylibsignal_emit_unlocked_R + 2993 frame #13: 0x0000000100b5e834 libgobject-2.0.0.dylibg_signal_emit_valist + 2164
    frame #14: 0x0000000100b5eeb6 libgobject-2.0.0.dylibg_signal_emit + 134 frame #15: 0x00000001003c82d8 libgtk-quartz-2.0.0.dylibgtk_object_dispose + 40
    frame #16: 0x0000000100b4c852 libgobject-2.0.0.dylibg_object_unref + 210 frame #17: 0x0000000100b4abbf libgobject-2.0.0.dylibg_cclosure_marshal_VOID__OBJECTv + 175
    frame #18: 0x0000000100b4768a libgobject-2.0.0.dylib_g_closure_invoke_va + 282 frame #19: 0x0000000100b5e57b libgobject-2.0.0.dylibg_signal_emit_valist + 1467
    frame #20: 0x0000000100b5eeb6 libgobject-2.0.0.dylibg_signal_emit + 134 frame #21: 0x000000010001c815 libgeany.0.dylibremove_page(page_num=0) + 229 at document.c:737
    frame #22: 0x000000010001c669 libgeany.0.dylib`document_close [inlined] document_remove_page(page_num=<unavailable>) + 7 at document.c:795

What I believe is happening here is that in #8 ScintillaGTK gets unreffed so at the point the ::Destroy() function is called it has 0 references.

In my opinion the gtk_widget_unparent() should be called in what corresponds to _dispose() in GTK. I'm not really familiar with C++ bindings but the ::Destroy() method seems to correspond to GTK's finalize().

(The OSX Gtk backend is sometimes a bit strange so it may behave a bit differently than on Linux.)

Discussion

  • Neil Hodgson

    Neil Hodgson - 2015-11-06

    GTK+ on OS X is outside my experience. Your explanation of "dispose" seems to be in accord with the API documentation. Do you want to produce a patch for this?

     
  • Jiri Techet

    Jiri Techet - 2015-11-06

    There's nothing OS X specific really. See the attached patch. I tried to follow the style of Destroy() and added the try block even though nothing should throw an exception (but might be useful if something throwing an exception is added in the future). The dispose() seems to be called alright and fixes the issue for me.

     
  • Neil Hodgson

    Neil Hodgson - 2015-11-09
    • labels: --> scintilla, gtk, os x
    • status: open --> open-fixed
    • assigned_to: Neil Hodgson
     
  • Neil Hodgson

    Neil Hodgson - 2015-11-12

    I am now seeing crashes in gtk_widget_unparent / ScintillaGTK::MainForAll / ScintillaGTK::ForAll when closing the about box in SciTE which contains a Scintilla instance.

     
  • Jiri Techet

    Jiri Techet - 2015-11-12

    Just tried but I can't reproduce it here. Could you post a full backtrace?

     
    • Neil Hodgson

      Neil Hodgson - 2015-11-12

      This is on Lubuntu 15.10.

      #0  0x00007ffff7828be0 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #1  0x00000000005bc3fc in ScintillaGTK::ForAll (this=0xdfcc00, callback=0x7ffff7828f70, callback_data=0x0) at ScintillaGTK.cxx:621
      #2  0x00000000005bc48d in ScintillaGTK::MainForAll (container=0xf136f0, include_internals=1, callback=0x7ffff7828f70, callback_data=0x0) at ScintillaGTK.cxx:632
      #3  0x00007ffff783c7d2 in gtk_widget_unparent () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #4  0x00007ffff75f7e63 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #5  0x00007ffff6645117 in g_cclosure_marshal_VOID__OBJECTv () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #6  0x00007ffff6642244 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #7  0x00007ffff665ca46 in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #8  0x00007ffff665d12f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #9  0x00007ffff763d99c in gtk_container_remove () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #10 0x00007ffff7837df5 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #11 0x00000000005c30d8 in ScintillaGTK::Dispose (object=0xf136f0) at ScintillaGTK.cxx:2602
      #12 0x00007ffff66487b8 in g_object_run_dispose () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #13 0x00007ffff75f7d77 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #14 0x00007ffff763f530 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #15 0x00007ffff6641f6f in g_closure_invoke () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #16 0x00007ffff665457e in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #17 0x00007ffff665cdfc in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #18 0x00007ffff665d12f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #19 0x00007ffff7837e88 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #20 0x00007ffff66487b8 in g_object_run_dispose () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #21 0x00007ffff7840999 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #22 0x00007ffff763f530 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #23 0x00007ffff6642015 in g_closure_invoke () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #24 0x00007ffff665457e in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #25 0x00007ffff665cdfc in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #26 0x00007ffff665d12f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #27 0x00007ffff7837e88 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #28 0x00007ffff7847a20 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #29 0x00007ffff66487b8 in g_object_run_dispose () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #30 0x00000000005306c3 in messageBoxOK (p=0x0) at SciTEGTK.cxx:847
      #31 0x00007ffff6642015 in g_closure_invoke () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #32 0x00007ffff6654061 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #33 0x00007ffff665cdfc in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #34 0x00007ffff665d12f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #35 0x00007ffff76053fd in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #36 0x00007ffff7605465 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #37 0x00007ffff6642244 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #38 0x00007ffff665ca46 in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #39 0x00007ffff665d12f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #40 0x00007ffff76034f0 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #41 0x00007ffff093ed90 in ffi_call_unix64 () from /usr/lib/x86_64-linux-gnu/libffi.so.6
      #42 0x00007ffff093e7f8 in ffi_call () from /usr/lib/x86_64-linux-gnu/libffi.so.6
      #43 0x00007ffff6642d65 in g_cclosure_marshal_generic_va () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #44 0x00007ffff6642244 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #45 0x00007ffff665ca46 in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #46 0x00007ffff665d12f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #47 0x00007ffff76ac091 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #48 0x00007ffff6644e2e in g_cclosure_marshal_VOID__BOXEDv () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #49 0x00007ffff6642244 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #50 0x00007ffff665ca46 in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #51 0x00007ffff665d12f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #52 0x00007ffff76a96ae in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #53 0x00007ffff76aaafb in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #54 0x00007ffff76ad535 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #55 0x00007ffff768025b in gtk_event_controller_handle_event () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #56 0x00007ffff782896d in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #57 0x00007ffff76f237a in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #58 0x00007ffff6642192 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #59 0x00007ffff665c558 in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #60 0x00007ffff665d12f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #61 0x00007ffff782c284 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #62 0x00007ffff76ef81e in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #63 0x00007ffff76f14ce in gtk_main_do_event () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #64 0x00007ffff726d322 in ?? () from /usr/lib/x86_64-linux-gnu/libgdk-3.so.0
      #65 0x00007ffff6168ff7 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
      #66 0x00007ffff6169250 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
      #67 0x00007ffff61692fc in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
      #68 0x00007ffff76f0815 in gtk_main_iteration () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #69 0x000000000053b8ab in SciTEGTK::WindowMessageBox (this=0x7fffffffb7c0, w=..., msg="SciTE\nby Neil Hodgson neilh@scintilla.org .", style=1048576) at SciTEGTK.cxx:3164
      #70 0x000000000053baf4 in SciTEGTK::AboutDialog (this=0x7fffffffb7c0) at SciTEGTK.cxx:3183
      #71 0x000000000056afd4 in SciTEBase::MenuCommand (this=0x7fffffffb7c0, cmdID=902, source=0) at ../src/SciTEBase.cxx:3063
      #72 0x000000000053174d in SciTEGTK::Command (this=0x7fffffffb7c0, wParam=902) at SciTEGTK.cxx:1131
      #73 0x000000000053be00 in SciTEGTK::MenuSignal (menuitem=0xe5cc40, scitew=0x7fffffffb7c0) at SciTEGTK.cxx:3266
      #74 0x00007ffff6642015 in g_closure_invoke () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #75 0x00007ffff6654061 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #76 0x00007ffff665cdfc in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #77 0x00007ffff665d12f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #78 0x00007ffff782b29e in gtk_widget_activate () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #79 0x00007ffff7710736 in gtk_menu_shell_activate_item () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #80 0x00007ffff7710a64 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #81 0x00007ffff76f237a in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #82 0x00007ffff6642244 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #83 0x00007ffff665c558 in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #84 0x00007ffff665d12f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
      #85 0x00007ffff782c284 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #86 0x00007ffff76ef81e in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #87 0x00007ffff76f14ce in gtk_main_do_event () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #88 0x00007ffff726d322 in ?? () from /usr/lib/x86_64-linux-gnu/libgdk-3.so.0
      #89 0x00007ffff6168ff7 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
      #90 0x00007ffff6169250 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
      #91 0x00007ffff6169572 in g_main_loop_run () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
      #92 0x00007ffff76f0775 in gtk_main () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
      #93 0x0000000000547c59 in SciTEGTK::Run (this=0x7fffffffb7c0, argc=1, argv=0x7fffffffe1f8) at SciTEGTK.cxx:5334
      #94 0x0000000000547e91 in main (argc=1, argv=0x7fffffffe1f8) at SciTEGTK.cxx:5386
      
       
  • Jiri Techet

    Jiri Techet - 2015-11-13

    OK, tried on normal Ubuntu 15.10 but couldn't reproduce it.

    However, I checked what GtkScrolledWindow does and it also keeps a reference to the scroll bars (also uses destroy() instead of dispose() but this shouldn't matter IMO). Holding a reference to the scrollbar guarantees that the scrollbar object isn't destroyed in the middle of unparent() and that something else doesn't use the invalid object. Would you try if the attached patch helps?

     
    • Colomban Wendling

      The GObject docs state that

      When dispose ends, the object should not hold any reference to any other member object. The object is also expected to be able to answer client method invocations (with possibly an error code but no memory violation) until finalize is executed. dispose can be executed more than once. dispose should chain up to its parent implementation just before returning to the caller.

      So AFAICT (and AFAIK), dispose() is supposed to do what you initially did, but you also need to make ForAll() proof against scrollbars being NULL (and potentially all other access, but I highly doubt anything else where it's used can be called after dispose() anyway).

      This said, in practice AFAIK this requirement of dropping references is to avoid cyclic references or something, by having all objects releasing each other's reference and only after that actually destroying the object; so it probably doesn't really matter here.

       
      • Jiri Techet

        Jiri Techet - 2015-11-13

        Ah, right, I misread the stack trace - I thought the crash happened during the invocation of unparent() in which case the scroll bars don't have the NULL value yet so the check wouldn't solve anything. But actually it happens in the super chain-up call so the crash must be caused by the NULL value - I'll send a new patch.

         
  • Jiri Techet

    Jiri Techet - 2015-11-13

    Here's the NULL check patch.

     
    • Neil Hodgson

      Neil Hodgson - 2015-11-13

      Comitted [876661].

       

      Related

      Commit: [876661]

      • Colomban Wendling

        @nyamatongwe do you confirm this fixed the crash you've been seeing? I'd like to backport this to Geany's 3.6.1 (https://github.com/geany/geany/pull/746), but as I wasn't able to reproduce any of this (neither @techee's warnings, nor yours with his patch, and not even in a Lubuntu VM), I'd rather be sure not to import something known to be buggy :)

         
        • Neil Hodgson

          Neil Hodgson - 2015-11-14

          Yes, the patch fixes the crash.

           
  • Neil Hodgson

    Neil Hodgson - 2016-01-04

    From Mitchell Foral:

    My application now throws the following assertion errors upon calling gtk_widget_destroy() on Scintilla widgets:

    Gtk-CRITICAL **: IAgtk_widget_unmap: assertion** `GTK_IS_WIDGET (widget)' failed

    Gtk-CRITICAL **: IA__gtk_widget_unrealize: assertion `GTK_IS_WIDGET (widget)' failed

    Gtk-CRITICAL **: IA__gtk_widget_unrealize: assertion `GTK_IS_WIDGET (widget)' failed

    I've tracked these errors to `ScintillaGTK::UnRealizeThis()` and marked them with an '*' in the code snippet below.

        gtk_selection_clear_targets(widget, GDK_SELECTION_PRIMARY);
    
        if (IS_WIDGET_MAPPED(widget)) {
    *       gtk_widget_unmap(widget);
        }
    #if GTK_CHECK_VERSION(2,20,0)
        gtk_widget_set_realized(widget, FALSE);
    #else
        GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
    #endif
        gtk_widget_unrealize(PWidget(wText));
    *   gtk_widget_unrealize(PWidget(scrollbarv));
    *   gtk_widget_unrealize(PWidget(scrollbarh));
        gtk_widget_unrealize(PWidget(wPreedit));
        gtk_widget_unrealize(PWidget(wPreeditDraw));
        g_object_unref(im_context);
        im_context = NULL;
        if (GTK_WIDGET_CLASS(parentClass)->unrealize)
            GTK_WIDGET_CLASS(parentClass)->unrealize(widget);
    
        Finalise();
    

    The referenced changeset sets `scrollbarv` and `scrollbarh` to `NULL`, so the widget assertion error makes sense. However, the unmap call is weird because a `GTK_IS_WIDGET(widget)` test succeeds and unmap() is always called.

    When I comment out the

    object_class->dispose = Dispose;
    

    introduced in the referenced changeset, my assertion errors go away.

     
  • Jiri Techet

    Jiri Techet - 2016-01-05

    I can't imagine how unrealize() could be called by Gtk after dispose (and if it was called before, the scrollbar widgets wouldn't be NULL). What I rather suspect here is that Mitchell over-destroys the Scintilla widget. From the Textadept screenshots it seems it uses a GtkNotebook for tabs. Now if he places the Scintilla widget inside the notebook's tab, all he needs to do to destroy the Scintilla widget is to call gtk_notebook_remove_page() - it should unref its children including the Scintilla widget that shuld get properly destroyed by this. Any explicit gtk_widget_destroy() on the Scintilla widget is extra IMO.

    Mitchell could put some trace inside void ScintillaGTK::Destroy() to see if it gets called even without the explicit gtk_widget_destroy() call or to check if it gets called twice with the gtk_widget_destroy() call for a single file.

     
  • Jiri Techet

    Jiri Techet - 2016-01-05

    Forgot to mention that if the above isn't right, it would help to get a backgrace from gdb when running the editor with --g-fatal-warnings to know from where unrealize() gets called.

     
  • Neil Hodgson

    Neil Hodgson - 2016-01-18
    • status: open-fixed --> closed-fixed
     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks