gtk-rs / gtk

DEPRECATED, use https://github.com/gtk-rs/gtk3-rs repository instead!
https://gtk-rs.org/
MIT License
1.24k stars 82 forks source link

Safe code can cause segfault #1039

Closed antoyo closed 4 years ago

antoyo commented 4 years ago

Hi. The following code cause a segfault:

extern crate glib;
extern crate gtk;
extern crate gio;

use gtk::prelude::*;
use gio::prelude::*;

use gtk::{Application, Button, Window, WindowType};

fn main() {
    let application = Application::new(
        Some("com.github.gtk-rs.examples.basic"),
        Default::default(),
    ).expect("failed to initialize GTK application");

    application.connect_activate(|app| {
        let window = Window::new(WindowType::Toplevel);
        window.set_title("First GTK+ Program");
        window.set_default_size(350, 70);

        let button = Button::with_label("Click me!");
        button.connect_clicked(|_| {
            println!("Clicked!");
        });
        window.add(&button);

        window.show_all();

        let app = app.clone();
        gtk::timeout_add(100, move || {
            window.set_application(Some(&app));
            glib::Continue(false)
        });
    });

    application.run(&[]);
    gtk::main();
}

Here's the stacktrace:

#0  0x00007ffff789582a in  () at /usr/lib/libgtk-3.so.0
#1  0x00007ffff73447de in g_cclosure_marshal_VOID__OBJECTv () at /usr/lib/libgobject-2.0.so.0
#2  0x00007ffff736280a in g_signal_emit_valist () at /usr/lib/libgobject-2.0.so.0
#3  0x00007ffff7362980 in g_signal_emit () at /usr/lib/libgobject-2.0.so.0
#4  0x00007ffff7b3d473 in gtk_window_set_application () at /usr/lib/libgtk-3.so.0
#5  0x000055555555d6f7 in <O as gtk::auto::window::GtkWindowExt>::set_application (self=0x555555908488, application=...)
    at /home/antoyo/.cargo/registry/src/github.com-1ecc6299db9ec823/gtk-0.9.0/src/auto/window.rs:1573
#6  0x000055555555d0c5 in gtk_test::main::{{closure}}::{{closure}} () at src/main.rs:31
#7  0x000055555555e996 in glib::source::trampoline (func=0x555555908480) at /home/antoyo/.cargo/registry/src/github.com-1ecc6299db9ec823/glib-0.10.1/src/source.rs:90
#8  0x00007ffff725c764 in  () at /usr/lib/libglib-2.0.so.0
#9  0x00007ffff725c340 in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#10 0x00007ffff72aa1d9 in  () at /usr/lib/libglib-2.0.so.0
#11 0x00007ffff725ac03 in g_main_loop_run () at /usr/lib/libglib-2.0.so.0
#12 0x00007ffff79ce08f in gtk_main () at /usr/lib/libgtk-3.so.0
#13 0x000055555556151a in gtk::auto::functions::main () at /home/antoyo/.cargo/registry/src/github.com-1ecc6299db9ec823/gtk-0.9.0/src/auto/functions.rs:314
#14 0x000055555555dadb in gtk_test::main () at src/main.rs:37

I'm not sure exactly what is causing this. It might be because set_application() is called from outside the context of the activate signal.

sdroege commented 4 years ago

Install debug symbols for GTK and GLib/GObject please, then we would know the lines where things go wrong here and that should make it clear what happens :)

gtk_window_set_application() causes some signal to be emitted and a signal handler on that signal is exploding.

sdroege commented 4 years ago

Proper backtrace for reference:

Thread 1 (Thread 0x7ffff580cb80 (LWP 63334)):
#0  gtk_application_impl_window_added (impl=0x0, window=0x555555644530 [GtkWindow]) at ../../../../gtk/gtkapplicationimpl.c:90
#1  0x00007ffff790e7b8 in gtk_application_window_added (application=application@entry=0x5555555fc0f0 [GtkApplication], window=window@entry=0x555555644530 [GtkWindow]) at ../../../../gtk/gtkapplication.c:438
#2  0x00007ffff73392ff in g_cclosure_marshal_VOID__OBJECTv (closure=0x5555555fb510, return_value=<optimized out>, instance=<optimized out>, args=<optimized out>, marshal_data=<optimized out>, n_params=<optimized out>, param_types=0x5555555fb560) at ../../../gobject/gmarshal.c:1910
#3  0x00007ffff7336206 in _g_closure_invoke_va (closure=0x5555555fb510, return_value=0x0, instance=0x5555555fc0f0, args=0x7fffffffd8a0, n_params=1, param_types=0x5555555fb560) at ../../../gobject/gclosure.c:873
#4  0x00007ffff73548d4 in g_signal_emit_valist (instance=0x5555555fc0f0, signal_id=<optimized out>, detail=0, var_args=var_args@entry=0x7fffffffd8a0) at ../../../gobject/gsignal.c:3407
#5  0x00007ffff7354edf in g_signal_emit (instance=<optimized out>, signal_id=<optimized out>, detail=detail@entry=0) at ../../../gobject/gsignal.c:3554
#6  0x00007ffff790f222 in gtk_application_add_window (application=<optimized out>, window=window@entry=0x555555644530 [GtkWindow]) at ../../../../gtk/gtkapplication.c:976
#7  0x00007ffff7b95ac0 in gtk_window_set_application (window=0x555555644530 [GtkWindow], application=0x5555555fc0f0 [GtkApplication]) at ../../../../gtk/gtkwindow.c:3569
#8  0x000055555555d1c7 in <O as gtk::auto::window::GtkWindowExt>::set_application (self=0x555555742ed8, application=...) at /home/slomo/.cargo/git/checkouts/gtk-b89af3a825b1a0bb/b0a081e/src/auto/window.rs:1573
#9  0x000055555555cd25 in bah::main::{{closure}}::{{closure}} () at src/main.rs:31
#10 0x000055555555e226 in glib::source::trampoline (func=0x555555742ed0, func@entry=<error reading variable: value has been optimized out>) at /home/slomo/.cargo/git/checkouts/glib-928cf7b282977403/0f--Type <RET> for more, q to quit, c to continue without paging--
48fab/src/source.rs:90
#11 0x00007ffff724c054 in g_timeout_dispatch (source=0x5555557a4690, callback=<optimized out>, user_data=<optimized out>) at ../../../glib/gmain.c:4800
#12 0x00007ffff724b4de in g_main_dispatch (context=0x5555555fdbf0) at ../../../glib/gmain.c:3309
#13 g_main_context_dispatch (context=context@entry=0x5555555fdbf0) at ../../../glib/gmain.c:3974
#14 0x00007ffff724b890 in g_main_context_iterate (context=0x5555555fdbf0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../../../glib/gmain.c:4047
#15 0x00007ffff724bb63 in g_main_loop_run (loop=0x5555555fdbb0) at ../../../glib/gmain.c:4241
#16 0x00007ffff7a38e85 in gtk_main () at ../../../../gtk/gtkmain.c:1328
#17 0x000055555556182a in gtk::auto::functions::main () at /home/slomo/.cargo/git/checkouts/gtk-b89af3a825b1a0bb/b0a081e/src/auto/functions.rs:314
sdroege commented 4 years ago

The reason is that priv->impl of GtkApplication is not initialized yet. It would only be once startup has run. This is a bug in GTK IMHO, it should at least get a guard against this situation to not crash. Inside gtk_application_window_added()

In theory this piece of code in gtk_application_add_window() should prevent it already but apparently doesn't:

  if (!g_application_get_is_registered (G_APPLICATION (application)))
    {
      g_critical ("New application windows must be added after the "
                  "GApplication::startup signal has been emitted.");
      return;
    }

Please report to GTK here: https://gitlab.gnome.org/GNOME/gtk/issues/new