Adw.ToastOverlay: Does it dismiss Toasts on its own if timeout is defined?

Heyho, I am once again working on contributing to a nim library that wraps gtk and provides the widgets etc. in a more declarative fashion.

I am currently wrapping Toast and ToastOverlay.
I’ve got something that I can at least show and a nicely compileable example, but that example segfaults in specific scenarios that make me think I am missing too much understanding of ToastOverlay. So I have the following questions:

  1. If ToastOverlay is given a pointer to a Toast which has timeout defined on it (set via adw_toast_set_timeout), does ToastOverlay automagically dismiss the Toast after that timeout or do I have to have some mechanism to do so?
  2. If I dismiss a Toast, does that trigger some freeing mechanism after a while?

Why am I asking this?
Currently I do not observe that ToastOverlay dismisses a Toast on its own.
So what I currently do is I set a timeout myself via g_timeout_add_full based on the value in Toast.timeout, and that then triggers adw_toast_dismiss after the timeout.

That is however seemingly problematic and causes segfaults when the User clicks on the toast to dismiss it and later my timeout expires and triggers dismissing the already dismissed Toast again.

I think this is because in the time between the manual dismissal and the timeout expiring the Toast memory might be freed by ToastOverlay (as ToastOverlay owns the Toast)?

I believe to have confirmed (via valgrind) that it is a use-after-free problem, caused by the toast getting free’d by the overlay once it is dismissed.

At least that is how I interpret these Valgrind logs (Note: I basically don’t know Jack when it comes to troubleshooting C and reading valgrind, my assumption is based entirely on Address 0x218ee550 is 0 bytes inside a block of size 88 free'd):

Valgrind logs

==1102175== Invalid read of size 8
==1102175== at 0x56B2E69: g_type_check_instance_is_a (gtype.c:4164)
==1102175== by 0x58AA37B: UnknownInlinedFun (adw-toast.h:28)
==1102175== by 0x58AA37B: adw_toast_dismiss (adw-toast.c:948)
==1102175== by 0x16E79A: dismiss__OOZOOZOOZowlkettleZadw_u4156 (adw.nim:800)
==1102175== by 0x16A3E4: call__OOZOOZOOZowlkettle_u197 (owlkettle.nim:106)
==1102175== by 0x573739D: g_timeout_dispatch (gmain.c:5121)
==1102175== by 0x5735F18: g_main_dispatch.lto_priv.0 (gmain.c:3476)
==1102175== by 0x57942B6: UnknownInlinedFun (gmain.c:4284)
==1102175== by 0x57942B6: g_main_context_iterate_unlocked.isra.0 (gmain.c:4349)
==1102175== by 0x5734111: g_main_context_iteration (gmain.c:4414)
==1102175== by 0x16A2FB: runMainloop__OOZOOZOOZowlkettleZmainloop_u391 (mainloop.nim:97)
==1102175== by 0x179D15: brew__OOZOOZOOZowlkettleZadw_u4177 (adw.nim:830)
==1102175== by 0x180F37: NimMainModule (toast_overlay.nim:77)
==1102175== by 0x115A66: NimMainInner (dataentries.nim:119)
==1102175== by 0x115A66: NimMain (dataentries.nim:130)
==1102175== by 0x115A66: main (dataentries.nim:138)
==1102175== Address 0x218ee550 is 0 bytes inside a block of size 88 free’d
==1102175== at 0x484412F: free (vg_replace_malloc.c:974)
==1102175== by 0x56B1BD0: g_type_free_instance (gtype.c:2076)
==1102175== by 0x58A90E3: free_toast_info (adw-toast-overlay.c:119)
==1102175== by 0x56ABB72: UnknownInlinedFun (gclosure.c:895)
==1102175== by 0x56ABB72: signal_emit_valist_unlocked (gsignal.c:3516)
==1102175== by 0x56ABC76: g_signal_emit_valist (gsignal.c:3355)
==1102175== by 0x56ABD33: g_signal_emit (gsignal.c:3675)
==1102175== by 0x58547D0: adw_animation_skip (adw-animation.c:716)
==1102175== by 0x58548EE: tick_cb (adw-animation.c:191)
==1102175== by 0x4BCFF53: gtk_widget_on_frame_clock_update.lto_priv.0 (gtkwidget.c:2985)
==1102175== by 0x568C6BF: g_closure_invoke (gclosure.c:832)
==1102175== by 0x56BAA35: signal_emit_unlocked_R.isra.0 (gsignal.c:3980)
==1102175== by 0x56ABA41: signal_emit_valist_unlocked (gsignal.c:3612)
==1102175== Block was alloc’d at
==1102175== at 0x48469B3: calloc (vg_replace_malloc.c:1554)
==1102175== by 0x574026A: g_malloc0 (gmem.c:163)
==1102175== by 0x56B7086: g_type_create_instance (gtype.c:1979)
==1102175== by 0x569CD90: g_object_new_internal.part.0 (gobject.c:2245)
==1102175== by 0x569EF0A: UnknownInlinedFun (gobject.c:2562)
==1102175== by 0x569EF0A: g_object_new_valist (gobject.c:2584)
==1102175== by 0x569F29D: g_object_new (gobject.c:2057)
==1102175== by 0x1790EE: newToast__OOZOOZOOZowlkettleZadw_u3899 (adw.nim:734)
==1102175== by 0x17EEB7: buildToast__toast95overlay_u161 (toast_overlay.nim:39)
==1102175== by 0x17F136: view__toast95overlay_u166 (toast_overlay.nim:37)
==1102175== by 0x130481: redraw__OOZOOZOOZowlkettleZwidgetdef_u234 (widgetdef.nim:78)
==1102175== by 0x135152: eventCallback__OOZOOZOOZowlkettleZwidgetutils_u17 (widgetutils.nim:48)
==1102175== by 0x56ABB72: UnknownInlinedFun (gclosure.c:895)
==1102175== by 0x56ABB72: signal_emit_valist_unlocked (gsignal.c:3516)

The answer is: Yes I was doing something wrong, and what hurts the most is that I just didn’t read the docs properly.

I saw “Time” and went “Ah, milliseconds”:

It immensely helps to actually read the docs:

The timeout of the toast, in seconds.

I was setting it in milliseconds, so of course I never saw it get dismissed by gtk.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.