Fixes random crashes caused by bad wrapper instance cache. #133
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
When you create a GObject, GI-Crystal adds a qdata to it with a pointer to the Crystal object, so if this object goes into C world and appear later in e.g. a signal callback, the Crystal object can be restored and all Crystal code there, including memory for the isntance variables will work as expected.
To avoid this object to be collected by GC is another subject.
This behavior is needed by user types, because we must be able to access the instance variables, etc. But for wrappers this isn't needed since it only holds a pointer to the C object, but GICrystal was doing this anyway to save some memory allocations, as we know:
Early optimization is the root of all evil
The problem is:
If you a signal with a GObject parameter that is really a
Gtk::ListView
the signal code will doGObject::Object.new(pointer, :none)
.This call will create the Crystal instance and save it in the qdata, so later when you do a cast like:
Gtk::ListView.cast
it seems to work, but it is returning the Crystal object for theGObject::Object
memory layout, due to unsafe code the compiler will believe us and think it's aGtk::ListView
.When you try to use some specific
Gtk::ListView
method a crash can happen depending on how the compiler decided to do such method call, since the type id is for a different type it will just crash, I'm not sure if Crystal uses a vtable for that, if so this also explains the error.Solution
Remove the cache for non-user types fixes the problem. But to make wrapper objects more Crystal-like the
self.new
was modified to identify the GType and call the right wrapper.new
method for it.This means that is possible now to use Crystal casts for wrapper objects!
This opens the possibility to avoid the Abstract classes created for each GObject interface, since we could simple do:
GObject::Object.new(ptr, :none).as(Interface)
And I tried, but crashed the compiler 😅.