rust-qt / ritual

Use C++ libraries from Rust
Apache License 2.0
1.22k stars 49 forks source link

using qactiongroup causes segfault on quit #92

Closed jlgerber closed 4 years ago

jlgerber commented 4 years ago

It seems like there is something going on here. When I introduce a QActionGroup, I get a segfault on quit. I don't see what i am doing wrong here, based on the type signatures... I am running on os x using qt version 5.13.2 / 5.14.0

Here is a simple repro:

#![windows_subsystem = "windows"]
use qt_core::{QString, ToolButtonStyle};
use qt_widgets::{cpp_core::CppBox, QAction, QActionGroup, QApplication, QMainWindow, QWidget};

pub fn qs<S: AsRef<str>>(input: S) -> CppBox<QString> {
    QString::from_std_str(input.as_ref())
}

struct Form {
    _main: CppBox<QMainWindow>,
    _actiongrp: CppBox<QActionGroup>,
    _action1: CppBox<QAction>,
    _action2: CppBox<QAction>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    QApplication::init(|_app| unsafe {
        // create main window
        let mut mw = QMainWindow::new_0a();
        mw.set_central_widget(QWidget::new_0a().into_ptr());
        // create toolbar
        let mut toolbar_ptr = mw.add_tool_bar_q_string(&qs("toolbar"));
        toolbar_ptr.set_tool_button_style(ToolButtonStyle::ToolButtonTextOnly);
        //create action group
        let mut actiongroup = QActionGroup::new(toolbar_ptr);
        let actiongroup_ptr = actiongroup.as_mut_ptr();
        // create action 1
        let mut action1 = QAction::from_q_object(actiongroup_ptr);
        action1.set_icon_text(&qs("Foo"));
        toolbar_ptr.add_action(action1.as_mut_ptr());
        // create action 2
        let mut action2 = QAction::from_q_object(actiongroup_ptr);
        action2.set_icon_text(&qs("Bar"));
        toolbar_ptr.add_action(action2.as_mut_ptr());
        mw.show();
        let mut _form = Form {
            _main: mw,
            _actiongrp: actiongroup,
            _action1: action1,
            _action2: action2,
        };
        QApplication::exec()
    });
}
Riateche commented 4 years ago

Looks like double free. All the content of the window is owned by it, so when CppBox<QMainWindow> gets dropped, all containing objects are deleted as well. But CppBox<QActionGroup> and CppBox<QAction> will also try to delete their objects, resulting in UB. You should use into_ptr() on a CppBox object when you pass ownership of the object elsewhere. In case of QAction::from_q_object, the constructed object is already owned by its parent, so you should call into_ptr() on it immediately.

jlgerber commented 4 years ago

Interesting. ok that worked. I had to call into_ptr on the actions and the actiongroup. I figured that it was a double free, the ownership wasnt clear to me. Normally I call into_ptr() when i transfer ownership to qt (at least that is how i think if it). However, the docs make it sound like i own QAction...