Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not maintaining a reference to Objects causes errors #20

Closed
rationalis-petra opened this issue Jun 11, 2023 · 3 comments
Closed

Not maintaining a reference to Objects causes errors #20

rationalis-petra opened this issue Jun 11, 2023 · 3 comments

Comments

@rationalis-petra
Copy link

rationalis-petra commented Jun 11, 2023

In sbcl, some (all?) gtk objects seem to requite a persistent reference originating from within the lisp program, otherwise upon garbage collection the object will be deleted (even if there are references to that object from other gtk objects).

To demonstrate the issue I've written a short script (assuming quicklisp is installed).

(ql:quickload '(:cl-gtk4 :cl-glib :bordeaux-threads))

(defun wait-trigger-gc ()
  (sleep 5)
  (sb-ext:gc))

(defvar *shortcuts* nil)
(defvar *window* nil)

(defun start (app)
  (let ((window (gtk4:make-application-window :application app))
        (shortcuts (gtk4:make-shortcut-controller)))

    (setf (gtk4:window-title window) "Test")
    (gtk4:widget-add-controller window shortcuts)
    ;; (setf *shortcuts* shortcuts)
    ;; (setf *window* window)

    (unless (gtk4:widget-visible-p window)
      (gtk4:window-present window))))

(defun run-app ()
  (let ((app (gtk4:make-application
              :application-id "org.rationalis-petra.test"
              :flags gio:+application-flags-flags-none+)))
    (gtk:connect app "activate" #'start)
    (unwind-protect (gio:application-run app nil)
      (progn
        (mapcar (alexandria:compose
                 #'gtk4:window-close
                 (alexandria:rcurry #'gobj:pointer-object 'window))
                (glib:glist-list (gtk4:application-windows app)))
        (glib:idle-add (lambda () (gio:application-quit app)))))))

(defun run-test ()
  (bt:make-thread #'wait-trigger-gc)
  (run-app))

(run-test)

On my system (intel laptop running Linux/EndeavourOS), executing with sbcl --load <filename> results in the following behaviour:

  • By default, after 5 seconds (i.e. when gc is forcibly triggered), the application will report the following error message:

    (sbcl:20304): Gdk-WARNING **: 14:14:19.069: gdk_gl_context_make_current() failed
    
    (sbcl:20304): GLib-GObject-CRITICAL **: 14:14:19.069: g_object_unref: assertion 'G_IS_OBJECT (object)' failed
    0
    

    Sometimes, it will drop you into ldb, and sometimes the application crashes outright.

  • If line (setf *window* window) is uncommented, then after 5 seconds the controller will be deleted, so any event (mouse-move, keypress etc.) will result in sbcl reporting the following error:

    (sbcl:20404): Gtk-CRITICAL **: 14:16:56.782: gtk_event_controller_get_propagation_phase: assertion   'GTK_IS_EVENT_CONTROLLER (controller)' failed
    

    Further, trying to close the window will drop the user into ldb

  • Finally, if both lines are uncommented, then the application works as expected.

Whether or not this is a bug, I am unsure, but if it is expected behaviour I think it should be documented somewhere.

@rationalis-petra rationalis-petra changed the title Some objects will cause GC errors Not maintaining a reference to Objects causes errors Jun 11, 2023
@rationalis-petra
Copy link
Author

I've done some more investigation, and it seems that similar errors can occur even if the object created is not used in anything. I'm unsure if this is related or a separate issue, so I'm adding it in the comments here instead of editing the original issue.

Below is a modified version of the start function which creates a shortcut that is then unused (and hence can be gc'd).

(defun start (app)
  (let ((window (gtk4:make-application-window :application app))
        (unused-shortcut
          (gtk4:make-shortcut
           :trigger (gtk4:shortcut-trigger-parse-string :string "<Ctrl>C")
           :action (gtk4:shortcut-action-parse-string :string "action(window.do_stuff)"))))

    (format t "shortcut: ~A~%" unused-shortcut)
    (setf (gtk4:window-title window) "Test")
    (setf *window* window)

    (unless (gtk4:widget-visible-p window)
      (gtk4:window-present window))))

Running the script with this modification with this modification resulted in the following output:

shortcut: #<OBJECT-INSTANCE {1004746613}>
CORRUPTION WARNING in SBCL pid 23868 tid 23869:
Memory fault at 0x100000001 (pc=0x7f47e15fcf61, fp=0x55979c866ba8, sp=0x7f47e184e768) tid 23869
The integrity of this image is possibly compromised.
Continuing with fingers crossed.
WARNING:
   Error calling finalizer #<FUNCTION (LAMBDA ()
                                        :IN
                                        GIR::OBJECT-SETUP-GC) {10047B092B}>:
  #<SB-SYS:MEMORY-FAULT-ERROR {10013B8273}>

@bohonghuang
Copy link
Owner

I'm sorry I'm unable to reproduce the issue you mentioned, but based on my experience, the documentation for the Widget.add_controller parameter in GTK4 is as follows:

The instance takes ownership of the data, and is responsible for freeing it.

I suspect that you may be using an older version of cl-gobject-introspection that does not handle object ownership correctly, which can result in some memory issues. Could you please update all the libraries to their latest versions and try again?

@rationalis-petra
Copy link
Author

rationalis-petra commented Jun 11, 2023

Looks like that was indeed the issue. Worth noting that to get it working, I had to manually clone the latest version - updating the quicklisp and uptralisp dists did not fix the issue on its own. From this I conclude it is likely that the version of cl-gobject-introspection on quicklisp is outdated.

Happy to close the issue if you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants