rhx / SwiftGtk

A Swift wrapper around gtk-3.x and gtk-4.x that is largely auto-generated from gobject-introspection
https://rhx.github.io/SwiftGtk/
BSD 2-Clause "Simplified" License
317 stars 26 forks source link

Dialog deinitialisation causes EXC_BAD_ACCESS #19

Closed Kiwijane3 closed 4 years ago

Kiwijane3 commented 4 years ago

I've encountered an issue where instances of the dialog class cause a EXC_BAD_ACCESS error during their deinit function. Specifically, this issue appears to be caused during the invocation of g_object_unref in the deinit of the Object class; The code is EXC_I386_GPFLT. I suspect the issue is caused by a pointer corruption at some point. I can't provide an example at this point, since the application I'm developing is proprietary. I'll try to build one I can release as soon as possible.

rhx commented 4 years ago

This typically happens when you get memory management wrong. While Swift uses automatic reference counting (ARC), glib/gtk you need to unref the objects you no longer need, but only if you are the owner.

This is why there is a Protocol and two Swift types for each glib/gtk type. The classes (e.g. Widget) use ARC while the structs (e.g. WidgetRef) don't, i.e., the latter are simple wrappers around the underlying glib/gtk pointers (that you need to do the memory management for).

I'm happy to have a look at an example once you have one.

Kiwijane3 commented 4 years ago

`import Gtk

let status = Application.run { app in let window = ApplicationWindowRef(application: app) window.title = "Hello, world" let test = Dialog(firstText: "", secondText: ""); window.setDefaultSize(width: 320, height: 240) let label = Label(str: "Hello, SwiftGtk") window.add(widget: label) window.showAll() }

guard let status = status else { fatalError("Could not create Application") } guard status == 0 else { fatalError("Application exited with status (status)") } `

That causes the fault. It only happens for dialogs in particular; Windows don't do it.

Kiwijane3 commented 4 years ago

The stack trace indicates this occurs during the gtk_widget_dispose function.

Kiwijane3 commented 4 years ago

I think it might be something to do with the initialisers for the varargs constructors. The issue doesn't occur if just use Dialog().

Kiwijane3 commented 4 years ago

This code seems to work: `import Gtk import GtkCHelpers

let status = Application.run { app in let window = ApplicationWindowRef(application: app) window.title = "Hello, world" let dialogPointer = gtk_c_helper_dialog_new_with_button("", window.ptr.assumingMemoryBound(to: GtkWindow.self), GTK_DIALOG_MODAL, "", GTK_RESPONSE_OK); let dialog = Dialog(retainingCPointer: dialogPointer!); window.setDefaultSize(width: 320, height: 240) let label = Label(str: "Hello, SwiftGtk") window.add(widget: label) window.showAll() }

guard let status = status else { fatalError("Could not create Application") } guard status == 0 else { fatalError("Application exited with status (status)") } `

So I think the issue is that the Dialog constructors aren't using the retaining constructors, which is causing issues. I'll write a patch and make a pull request.

Kiwijane3 commented 4 years ago

I've implemented a fix and made a pull request to resolve this issue.

rhx commented 4 years ago

Yes, it looks like there is a refSink() that's missing. I'll have a look. Until this is fixed, you can work around this by using:

    let test = Dialog(title: "Title", firstText: "", secondText: "")
    if test.isFloating { test.refSink() }
    // ...

[Edit:] No it looks like this indeed needs a ref() not a refSink()

rhx commented 4 years ago

Thanks!