Ferada / cl-cffi-gtk

#cl-cffi-gtk on Freenode. A Lisp binding to GTK+3. SBCL/CCL/ABCL (ECL/CLISP unstable)
http://www.crategus.com/books/cl-cffi-gtk
41 stars 8 forks source link

Boxed conversion needs to be fixed #20

Open Ferada opened 6 years ago

Ferada commented 6 years ago

E.g. a property of type GVariantType (which is basically an alias for char*) will fail to properly be translated onto the Lisp side. A bad fix (leaking memory) for this one particular case would be:

(defmethod parse-g-value-for-type (gvalue-ptr
                                   (type-numeric (eql (gtype "GBoxed"))))
  (if (g-type= (g-value-type gvalue-ptr) (g-type-strv))
      (convert-from-foreign (g-value-get-boxed gvalue-ptr)
                            '(g-strv :free-from-foreign nil))
      (let* ((boxed-type
               (get-g-boxed-foreign-info-for-gtype (g-value-type gvalue-ptr)))
             (result (boxed-parse-g-value gvalue-ptr boxed-type)))
        (if (g-type= (g-value-type gvalue-ptr) (g-type-from-name "GVariantType"))
            (g-variant-type-copy result)
            result))))

Basically copying the boxed value, which would otherwise be unref-ed and therefore could point to invalid memory once examined on the Lisp side.

It seems like one more case of having to specify :free-from-foreign/:free-to-foreign depending on the situation (if the boxed value is static there might be no need?). Alternatively the conversion could be done before the boxed value is being invalidated?

stacksmith commented 5 years ago

Are you giving up on this, or is this somehow resolved? I am always suspect of hidden data on foreign side...

Ferada commented 5 years ago

It's not solved no. At the moment I'm out of ideas of how to proceed here though.

stacksmith commented 5 years ago

The situation may be much worse than I thought.
So I am trying to figure out what happens to gtk-text-iters. As noted in this issue, @crategus mistakenly allocates new iters in every gtk-text-buffer and gtk-text-view function designed to mutate existinging iters. This results in thousands of iters generated while editing. The function to free them, gtk-text-iter-free is not defined. Is there some hidden dealocator? Iters are defined as boxed opaque types, and while I don't yet understand the implementation, it looks like define-g-boxed-opaque macro has a provision for a finalizer for these. Inspecting the symbol gtk::gtk-text-iter yields

NAME: @0=GTK-TEXT-ITER
TYPE: "GtkTextIter"
ALLOC: NIL
FREE: NIL

I tried to modify make-boxed-free-finalizer to print something to see if it ever runs, but it does not appear to. It is possible that it is running in some thread that has no standard-output. So i created a counter, and added an incf to the function. Nope. 0. It is never called, apparently. Edit: I also tried to see who calls gobject::g-boxed-type-register-static, which stores a user copy and deallocator functions... Apparently there are no callers. Also, no one seems to call g-boxed-free.

So as far as I can tell, iters are never deallocated.

Ferada commented 5 years ago

A lot of this is historic code btw., coming from cl-gtk2, not specifically how it was further developed in cl-cffi-gtk, especially the way the iterators etc. have been introduced. Wrt. the other tickets, I agree that it's not ideal, yes.

That said, I'm pretty sure the deallocation happens via the finalizers (and then via g-idle-add - you might simply not see that triggering in test code). Take a look at activate-gboxed-gc-hooks and then enable the logs in gobject.init.lisp, all the special variables at the top essentially, *debug-gc* e.g.

stacksmith commented 5 years ago

I am not judging anyone for bad code... Just trying to figure it out (thanks for the pointers, I will try to track it down). In case of iters, I found that at the very least: 1) They are allocated by creating a blank foreign structure with 14 slots, calling the copy function, and deallocating the said structure; 2) They are allocated every time a buffer or view position function is called instead of using existing iters;

I am having trouble with debug logs as the logger calls print-object on gobject-class derived objects while they are being constructed, so a bunch of my print-object implementations crash trying to print slots that are not yet there... EDIT: actually, it crashes trying to print gtk-text-mark, so I don't know how to procede. EDIT: never mind, debugging. So it looks like iters are never deallocated, and nothing ever goes to gboxed-gc-hooks that I can catch.