Segfault when using GtkListView and custom widgets
System information
What is your operating system and version? Fedora 35
What is your version of GJS? 1.70.0
Bug information
Steps to reproduce
Run this script:
test.js
imports.gi.versions.Gtk = '4.0';
const {GLib, GObject, Gio, Gtk} = imports.gi;
const ByteArray = imports.byteArray;
Gtk.init();
const Window = GObject.registerClass({
GTypeName: 'Window',
Template: ByteArray.fromString(`
<interface>
<template class="Window" parent="GtkWindow">
<property name="default-width">600</property>
<property name="default-height">400</property>
<property name="child">
<object class="GtkScrolledWindow">
<property name="vexpand">True</property>
<property name="child">
<object class="GtkListView">
<property name="model">
<object class="GtkNoSelection">
<property name="model" bind-property="model" bind-source="Window"/>
</object>
</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes">
<![CDATA[
<interface>
<template class="GtkListItem">
<property name="child">
<object class="Row">
<binding name="string-object">
<lookup name="item">GtkListItem</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]>
</property>
</object>
</property>
</object>
</property>
</object>
</property>
</template>
</interface>
`),
Properties: {
'model': GObject.ParamSpec.object(
'model',
'List of strings',
'A GtkStringList',
GObject.ParamFlags.READWRITE,
Gtk.StringList.$gtype
),
},
}, class Window extends Gtk.Window {});
const Row = GObject.registerClass({
GTypeName: 'Row',
Template: ByteArray.fromString(`
<interface>
<template class="Row" parent="GtkBox">
<child>
<object class="GtkLabel">
<binding name="label">
<lookup name="string" type="GtkStringObject">
<lookup name="string-object">Row</lookup>
</lookup>
</binding>
</object>
</child>
</template>
</interface>
`),
Properties: {
'string-object': GObject.ParamSpec.object(
'string-object',
'String object',
'A GtkStringObject',
GObject.ParamFlags.READWRITE,
Gtk.StringObject.$gtype
),
},
}, class Row extends Gtk.Box {});
const loop = GLib.MainLoop.new(null, false);
const win = new Window({model: Gtk.StringList.new(['test'])});
win.connect('close-request', () => loop.quit());
win.present();
loop.run();
Current behaviour
When closing the window, a segmentation fault happens.
Stack trace
#0 JSAutoRealm::JSAutoRealm(JSContext*, JSObject*) (this=this@entry=0x7fffffffcd40, cx=cx@entry=0x5555555c8ad0, target=0x0, this=<optimized out>, cx=<optimized out>, target=<optimized out>) at /usr/src/debug/mozjs78-78.15.0-1.fc35.x86_64/jsapi.cpp:564
#1 0x00007ffff7ed8f3d in gjs_object_set_gproperty(GObject*, unsigned int, GValue const*, GParamSpec*) (object=<optimized out>, property_id=<optimized out>, value=0x7fffffffcdb0, pspec=0x55555586a450) at ../gi/gobject.cpp:177
priv = 0x555555918950
cx = 0x5555555c8ad0
js_obj =
{<js::RootedBase<JSObject*, JS::Rooted<JSObject*> >> = {<js::MutableWrappedPtrOperations<JSObject*, JS::Rooted<JSObject*> >> = {<js::WrappedPtrOperations<JSObject*, JS::Rooted<JSObject*> >> = {<No data fields>}, <No data fields>}, <No data fields>}, stack = 0x5555555c8ae8, prev = 0x0, ptr = 0x0}
ar = {cx_ = 0x55555586a450, oldRealm_ = 0x7ffff7d147fe <g_param_value_validate+206>}
#2 0x00007ffff7d14996 in object_set_property (object=object@entry=0x5555555bb980, pspec=0x55555586a450, value=value@entry=0x7fffffffce80, nqueue=nqueue@entry=0x7fffcc14f790) at ../gobject/gobject.c:1571
tmp_value =
{g_type = 0x55555587d4a0 [None], data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
class = 0x555555882590
param_id = 1
redirect = <optimized out>
#3 0x00007ffff7d168e4 in g_object_setv (values=<optimized out>, names=<optimized out>, n_properties=<optimized out>, object=0x5555555bb980) at ../gobject/gobject.c:2416
i = <optimized out>
nqueue = 0x7fffcc14f790
pspec = <optimized out>
obj_type = Python Exception <class 'TypeError'>: can only concatenate str (not "NoneType") to str
__func__ = "g_object_setv"
#4 g_object_setv (object=0x5555555bb980, n_properties=<optimized out>, names=<optimized out>, values=<optimized out>) at ../gobject/gobject.c:2390
__func__ = "g_object_setv"
#5 0x00007ffff7d169af in g_object_set_property (object=<optimized out>, property_name=<optimized out>, value=value@entry=0x7fffffffce80) at ../gobject/gobject.c:2707
#6 0x00007fffee8e77c4 in gtk_expression_bind_notify (data=0x55555597a480) at ../gtk/gtkexpression.c:2102
value = {g_type = 0x50 [None], data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
bind = 0x55555597a480
#10 0x00007ffff7d23b33 in <emit signal ??? on instance ???> (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>) at ../gobject/gsignal.c:3553
var_args = {{gp_offset = 32, fp_offset = 48, overflow_arg_area = 0x7fffffffd300, reg_save_area = 0x7fffffffd240}}
#7 0x00007ffff7d05c2f in g_closure_invoke (closure=0x5555559a3e90, return_value=0x0, n_param_values=2, param_values=0x7fffffffd050, invocation_hint=0x7fffffffcfd0) at ../gobject/gclosure.c:830
marshal = 0x7ffff7d082a0 <g_cclosure_marshal_VOID__PARAM>
marshal_data = 0x0
in_marshal = 0
real_closure = 0x5555559a3e70
__func__ = "g_closure_invoke"
#8 0x00007ffff7d22056 in signal_emit_unlocked_R (node=node@entry=0x555555592190, detail=detail@entry=876, instance=instance@entry=0x55555592ec40, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fffffffd050) at ../gobject/gsignal.c:3742
tmp = <optimized out>
handler = 0x55555596d5c0
accumulator = 0x0
emission = {next = 0x0, instance = 0x55555592ec40, ihint = {signal_id = 1, detail = 876, run_type = (G_SIGNAL_RUN_FIRST | G_SIGNAL_ACCUMULATOR_FIRST_RUN)}, state = EMISSION_RUN, chain_type = 0x4 [None]}
hlist = <optimized out>
handler_list = 0x55555596d5c0
return_accu = 0x0
accu = {g_type = 0x0, data = {{v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}, {v_int = 0, v_uint = 0, v_long = 0, v_ulong = 0, v_int64 = 0, v_uint64 = 0, v_float = 0, v_double = 0, v_pointer = 0x0}}}
signal_id = 1
max_sequential_handler_number = 190
return_value_altered = 1
#9 0x00007ffff7d2391a in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fffffffd220) at ../gobject/gsignal.c:3497
instance_and_params = 0x7fffffffd050
signal_return_type = <optimized out>
param_values = 0x7fffffffd068
node = <optimized out>
i = <optimized out>
n_params = <optimized out>
__func__ = "g_signal_emit_valist"
#11 0x00007ffff7d0d254 in g_object_dispatch_properties_changed (object=0x55555592ec40, n_pspecs=<optimized out>, pspecs=<optimized out>) at ../gobject/gobject.c:1212
i = <optimized out>
#12 0x00007ffff7d15a5a in g_object_notify_by_spec_internal (pspec=<optimized out>, object=0x55555592ec40) at ../gobject/gobject.c:1305
nqueue = 0x0
notify_pspec = 0x55555592d4b0
pspec = <optimized out>
__func__ = "g_object_notify"
#13 g_object_notify (object=0x55555592ec40, property_name=<optimized out>) at ../gobject/gobject.c:1353
pspec = <optimized out>
__func__ = "g_object_notify"
#14 0x00007fffee94d5cb in gtk_list_item_widget_default_teardown (list_item=0x55555592ec40, self=0x555555960880) at ../gtk/gtklistitemwidget.c:543
priv = 0x555555960700
#15 gtk_list_item_factory_default_teardown (self=<optimized out>, widget=0x555555960880, list_item=0x55555592ec40) at ../gtk/gtklistitemfactory.c:94
#16 0x00007fffee949e02 in gtk_list_item_factory_teardown (self=0x55555596d480, widget=0x555555960880) at ../gtk/gtklistitemfactory.c:146
list_item = 0x55555592ec40
__func__ = "gtk_list_item_factory_teardown"
#17 0x00007fffeea63235 in gtk_widget_unroot (widget=0x555555960880) at ../gtk/gtkwidget.c:2520
priv = 0x555555960730
surface_transform_data = 0x0
#18 0x00007fffeea6339d in gtk_widget_forall (user_data=0x0, callback=0x7fffeea631d0 <gtk_widget_unroot>, widget=0x555555956320) at ../gtk/gtkwidget.c:11986
next = 0x0
child = <optimized out>
l = <optimized out>
#19 gtk_widget_real_unroot (widget=0x555555956320) at ../gtk/gtkwidget.c:777
l = <optimized out>
#20 0x00007fffeea63235 in gtk_widget_unroot (widget=0x555555956320) at ../gtk/gtkwidget.c:2520
priv = 0x5555559561d0
surface_transform_data = 0x0
#21 0x00007fffeea6339d in gtk_widget_forall (user_data=0x0, callback=0x7fffeea631d0 <gtk_widget_unroot>, widget=0x5555559583d0) at ../gtk/gtkwidget.c:11986
next = 0x5555555bb680
child = <optimized out>
l = <optimized out>
#22 gtk_widget_real_unroot (widget=0x5555559583d0) at ../gtk/gtkwidget.c:777
l = <optimized out>
#23 0x00007fffeea63235 in gtk_widget_unroot (widget=0x5555559583d0) at ../gtk/gtkwidget.c:2520
priv = 0x555555958280
surface_transform_data = 0x0
#24 0x00007fffeea634e7 in gtk_widget_unparent (widget=0x5555559583d0) at ../gtk/gtkwidget.c:2593
priv = 0x555555958280
old_parent = <optimized out>
old_prev_sibling = <optimized out>
root = 0x555555886280
__func__ = "gtk_widget_unparent"
#25 0x00007fffeea7da68 in gtk_window_dispose (object=0x555555886280) at ../gtk/gtkwindow.c:2575
_pp = 0x555555886040
_ptr = <optimized out>
window = 0x555555886280
priv = 0x555555886040
#26 0x00007ffff7d12b14 in g_object_unref (_object=<optimized out>) at ../gobject/gobject.c:3549
weak_locations = 0x55555597aab0
old_ref = <optimized out>
object = 0x555555886280
__func__ = "g_object_unref"
#27 g_object_unref (_object=0x555555886280) at ../gobject/gobject.c:3479
object = 0x555555886280
__func__ = "g_object_unref"
#28 0x00007ffff7ee074a in ObjectInstance::disassociate_js_gobject() (this=0x5555558845b0) at ../gi/object.cpp:1565
had_toggle_down = <optimized out>
had_toggle_up = <optimized out>
#29 0x00007ffff7f2fbf3 in std::function<void (ObjectInstance*)>::operator()(ObjectInstance*) const (__args#0=<optimized out>, this=0x7fffffffd620) at /usr/include/c++/11/bits/std_function.h:560
action = {<std::_Maybe_unary_or_binary_function<void, ObjectInstance*>> = {<std::unary_function<ObjectInstance*, void>> = {<No data fields>}, <No data fields>}, <std::_Function_base> = {static _M_max_size = 16, static _M_max_align = 8, _M_functor = {_M_unused = {_M_object = 0x7ffff7ee06d0 <ObjectInstance::disassociate_js_gobject()>, _M_const_object = 0x7ffff7ee06d0 <ObjectInstance::disassociate_js_gobject()>, _M_function_pointer = 0x7ffff7ee06d0 <ObjectInstance::disassociate_js_gobject()>, _M_member_pointer = (void (std::_Undefined_class::*)(std::_Undefined_class * const)) 0x7ffff7ee06d0 <ObjectInstance::disassociate_js_gobject()>}, _M_pod_data = "\320\006\356\367\377\177\000\000\000\000\000\000\000\000\000"}, _M_manager = 0x7ffff7ee6410 <std::_Function_handler<void (ObjectInstance*), std::_Mem_fn<void (ObjectInstance::*)()> >::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation)>}, _M_invoker = 0x7ffff7ee63f0 <std::_Function_handler<void (ObjectInstance*), std::_Mem_fn<void (ObjectInstance::*)()> >::_M_invoke(std::_Any_data const&, ObjectInstance*&&)>}
predicate = {<std::_Maybe_unary_or_binary_function<bool, ObjectInstance*>> = {<std::unary_function<ObjectInstance*, bool>> = {<No data fields>}, <No data fields>}, <std::_Function_base> = {static _M_max_size = 16, static _M_max_align = 8, _M_functor = {_M_unused = {_M_object = 0x7ffff7ed6930 <ObjectInstance::weak_pointer_was_finalized()>, _M_const_object = 0x7ffff7ed6930 <ObjectInstance::weak_pointer_was_finalized()>, _M_function_pointer = 0x7ffff7ed6930 <ObjectInstance::weak_pointer_was_finalized()>, _M_member_pointer = (void (std::_Undefined_class::*)(std::_Undefined_class * const)) 0x7ffff7ed6930 <ObjectInstance::weak_pointer_was_finalized()>}, _M_pod_data = "0i\355\367\377\177\000\000\000\000\000\000\000\000\000"}, _M_manager = 0x7ffff7ee6370 <std::_Function_handler<bool (ObjectInstance*), std::_Mem_fn<bool (ObjectInstance::*)()> >::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation)>}, _M_invoker = 0x7ffff7ee6330 <std::_Function_handler<bool (ObjectInstance*), std::_Mem_fn<bool (ObjectInstance::*)()> >::_M_invoke(std::_Any_data const&, ObjectInstance*&&)>}
__result = 0x55555587baa0
#30 operator() (link=0x5555558845b0, __closure=0x7fffffffd600) at ../gi/object.cpp:1120
action = {<std::_Maybe_unary_or_binary_function<void, ObjectInstance*>> = {<std::unary_function<ObjectInstance*, void>> = {<No data fields>}, <No data fields>}, <std::_Function_base> = {static _M_max_size = 16, static _M_max_align = 8, _M_functor = {_M_unused = {_M_object = 0x7ffff7ee06d0 <ObjectInstance::disassociate_js_gobject()>, _M_const_object = 0x7ffff7ee06d0 <ObjectInstance::disassociate_js_gobject()>, _M_function_pointer = 0x7ffff7ee06d0 <ObjectInstance::disassociate_js_gobject()>, _M_member_pointer = (void (std::_Undefined_class::*)(std::_Undefined_class * const)) 0x7ffff7ee06d0 <ObjectInstance::disassociate_js_gobject()>}, _M_pod_data = "\320\006\356\367\377\177\000\000\000\000\000\000\000\000\000"}, _M_manager = 0x7ffff7ee6410 <std::_Function_handler<void (ObjectInstance*), std::_Mem_fn<void (ObjectInstance::*)()> >::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation)>}, _M_invoker = 0x7ffff7ee63f0 <std::_Function_handler<void (ObjectInstance*), std::_Mem_fn<void (ObjectInstance::*)()> >::_M_invoke(std::_Any_data const&, ObjectInstance*&&)>}
predicate = {<std::_Maybe_unary_or_binary_function<bool, ObjectInstance*>> = {<std::unary_function<ObjectInstance*, bool>> = {<No data fields>}, <No data fields>}, <std::_Function_base> = {static _M_max_size = 16, static _M_max_align = 8, _M_functor = {_M_unused = {_M_object = 0x7ffff7ed6930 <ObjectInstance::weak_pointer_was_finalized()>, _M_const_object = 0x7ffff7ed6930 <ObjectInstance::weak_pointer_was_finalized()>, _M_function_pointer = 0x7ffff7ed6930 <ObjectInstance::weak_pointer_was_finalized()>, _M_member_pointer = (void (std::_Undefined_class::*)(std::_Undefined_class * const)) 0x7ffff7ed6930 <ObjectInstance::weak_pointer_was_finalized()>}, _M_pod_data = "0i\355\367\377\177\000\000\000\000\000\000\000\000\000"}, _M_manager = 0x7ffff7ee6370 <std::_Function_handler<bool (ObjectInstance*), std::_Mem_fn<bool (ObjectInstance::*)()> >::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation)>}, _M_invoker = 0x7ffff7ee6330 <std::_Function_handler<bool (ObjectInstance*), std::_Mem_fn<bool (ObjectInstance::*)()> >::_M_invoke(std::_Any_data const&, ObjectInstance*&&)>}
__result = 0x55555587baa0
#31 __gnu_cxx::__ops::_Iter_pred<ObjectInstance::remove_wrapped_gobjects_if(const Predicate&, const Action&)::<lambda(ObjectInstance*)> >::operator()<__gnu_cxx::__normal_iterator<ObjectInstance**, std::vector<ObjectInstance*> > > (__it=Python Exception <class 'gdb.error'>: value has been optimized out
, this=0x7fffffffd600) at /usr/include/c++/11/bits/predefined_ops.h:318
__result = 0x55555587baa0
#32 std::__remove_if<__gnu_cxx::__normal_iterator<ObjectInstance**, std::vector<ObjectInstance*> >, __gnu_cxx::__ops::_Iter_pred<ObjectInstance::remove_wrapped_gobjects_if(const Predicate&, const Action&)::<lambda(ObjectInstance*)> > > (__pred=..., __last=0x6f6d2e7365, __first=0x5555558845b0) at /usr/include/c++/11/bits/stl_algo.h:822
__result = 0x55555587baa0
#33 std::remove_if<__gnu_cxx::__normal_iterator<ObjectInstance**, std::vector<ObjectInstance*> >, ObjectInstance::remove_wrapped_gobjects_if(const Predicate&, const Action&)::<lambda(ObjectInstance*)> > (__pred=..., __last=Python Exception <class 'gdb.error'>: value has been optimized out
, __first=Python Exception <class 'gdb.error'>: value has been optimized out
) at /usr/include/c++/11/bits/stl_algo.h:894
#34 ObjectInstance::remove_wrapped_gobjects_if(std::function<bool (ObjectInstance*)> const&, std::function<void (ObjectInstance*)> const&) [clone .constprop.0] (predicate=..., action=...) at ../gi/object.cpp:1116
#35 0x00007ffff7ed65d2 in ObjectInstance::update_heap_wrapper_weak_pointers(JSContext*, JS::Compartment*, void*) () at ../gi/object.cpp:1412
#36 0x00007ffff60a492a in js::gc::GCRuntime::beginSweepingSweepGroup(JSFreeOp*, js::SliceBudget&) (this=0x5555555bc5c8, fop=0x7fffffffddc0, budget=<optimized out>) at /usr/src/debug/mozjs78-78.15.0-1.fc35.x86_64/gc/GC.cpp:1641
zone = {current = <optimized out>, selector = <optimized out>}
ap2 = {stats = <optimized out>, phaseKind = js::gcstats::PhaseKind::WEAK_COMPARTMENT_CALLBACK, enabled = true}
ap = {stats = <optimized out>, phaseKind = js::gcstats::PhaseKind::FINALIZE_START, enabled = true}
scc = {stats = <optimized out>, scc = 1, start = {mValue = {mUsedCanonicalNow = <optimized out>, mTimeStamp = 124811216167905}}}
sweepingAtoms = <optimized out>
#37 0x00007ffff609c4ce in sweepaction::SweepActionSequence::run(js::gc::SweepAction::Args&) (this=0x5555555caa40, args=...) at /usr/src/debug/mozjs78-78.15.0-1.fc35.x86_64/gc/GC.cpp:5981
iter = {maybeIter = @0x5555555caa60}
#38 0x00007ffff60b532a in sweepaction::SweepActionForEach<js::gc::SweepGroupsIter, JSRuntime*>::run(js::gc::SweepAction::Args&) (this=0x5555555cab40, args=...) at /usr/src/debug/mozjs78-78.15.0-1.fc35.x86_64/gc/GC.cpp:6016
iter = {maybeIter = @0x5555555cab60}
clearElem = {mExitFunction = {__this = 0x5555555cab40}, mExecuteOnDestruction = true}
#39 0x00007ffff60aba40 in js::gc::GCRuntime::performSweepActions(js::SliceBudget&) (budget=..., this=<optimized out>) at /usr/src/debug/mozjs78-78.15.0-1.fc35.x86_64/dist/include/mozilla/UniquePtr.h:287
fop = {runtime_ = 0x5555555bc0d0, freeLaterList = {<js::SystemAllocPolicy> = {<js::AllocPolicyBase> = {<No data fields>}, <No data fields>}, static kElemIsPod = true, static kInlineCapacity = 0, mBegin = 0x8, mLength = 0, mTail = {<mozilla::Vector<void*, 0, js::SystemAllocPolicy>::CapacityAndReserved> = {mCapacity = 0}, <No data fields>}}, jitPoisonRanges = {<js::SystemAllocPolicy> = {<js::AllocPolicyBase> = {<No data fields>}, <No data fields>}, static kElemIsPod = false, static kInlineCapacity = 0, mBegin = 0x18, mLength = 0, mTail = {<mozilla::Vector<js::jit::JitPoisonRange, 0, js::SystemAllocPolicy>::CapacityAndReserved> = {mCapacity = 0}, <No data fields>}}, isDefault = false, isCollecting_ = true}
args = {gc = 0x5555555bc5c8, fop = 0x7fffffffddc0, budget = @0x7fffffffe250}
progress = <optimized out>
disableBarriers = {gc = 0x5555555bc5c8}
performingGC = {cx = 0x5555555c8ad0}
destroyingRuntime = false
#40 js::gc::GCRuntime::incrementalSlice(js::SliceBudget&, mozilla::Maybe<JSGCInvocationKind> const&, JS::GCReason, js::gc::AutoGCSession&) (this=<optimized out>, budget=..., gckind=<optimized out>, reason=JS::GCReason::COMPONENT_UTILS, session=...) at /usr/src/debug/mozjs78-78.15.0-1.fc35.x86_64/gc/GC.cpp:6694
disableBarriers = {gc = 0x5555555bc5c8}
performingGC = {cx = 0x5555555c8ad0}
destroyingRuntime = false
#41 0x00007ffff60bb859 in js::gc::GCRuntime::gcCycle(bool, js::SliceBudget, mozilla::Maybe<JSGCInvocationKind> const&, JS::GCReason) (this=<optimized out>, nonincrementalByAPI=<optimized out>, budget=..., gckind=<optimized out>, reason=JS::GCReason::COMPONENT_UTILS) at /usr/src/debug/mozjs78-78.15.0-1.fc35.x86_64/gc/GC.cpp:7104
agc = {stats = @0x5555555bc620}
result = <optimized out>
session = {<js::gc::AutoHeapSession> = {gc = 0x5555555bc5c8, prevState = JS::HeapState::Idle, profilingStackFrame = {profiler_ = 0x0}}, maybeCheckAtomsAccess = {<mozilla::detail::MaybeStorage<js::gc::AutoCheckCanAccessAtomsDuringGC, true>> = {mStorage = {val = {<No data fields>}, dummy = 0 '\000'}, mIsSome = 1 '\001'}, <mozilla::detail::Maybe_CopyMove_Enabler<js::gc::AutoCheckCanAccessAtomsDuringGC, true, true, true>> = {<No data fields>}, <No data fields>}}
#42 0x00007ffff60bd602 in js::gc::GCRuntime::collect(bool, js::SliceBudget, mozilla::Maybe<JSGCInvocationKind> const&, JS::GCReason) (this=0x5555555bc5c8, nonincrementalByAPI=<optimized out>, budget=..., gckindArg=<optimized out>, reason=JS::GCReason::COMPONENT_UTILS) at /usr/src/debug/mozjs78-78.15.0-1.fc35.x86_64/gc/GC.cpp:7314
cycleResult = <optimized out>
gckind = {<mozilla::detail::MaybeStorage<JSGCInvocationKind, true>> = {mStorage = {val = GC_NORMAL, dummy = 0 '\000'}, mIsSome = 1 '\001'}, <mozilla::detail::Maybe_CopyMove_Enabler<JSGCInvocationKind, true, true, true>> = {<No data fields>}, <No data fields>}
repeat = <optimized out>
#43 0x00007ffff5cf5471 in js::gc::GCRuntime::gc(JSGCInvocationKind, JS::GCReason) (reason=JS::GCReason::COMPONENT_UTILS, gckind=GC_NORMAL, this=0x5555555bc5c8) at /usr/src/debug/mozjs78-78.15.0-1.fc35.x86_64/dist/include/js/SliceBudget.h:60
#44 JS_GC(JSContext*, JS::GCReason) (cx=0x5555555c8ad0, reason=reason@entry=JS::GCReason::COMPONENT_UTILS) at /usr/src/debug/mozjs78-78.15.0-1.fc35.x86_64/jsapi.cpp:1360
#45 0x00007ffff7efb735 in GjsContextPrivate::dispose() (this=0x5555555bb0a0) at ../gjs/context.cpp:426
gjs = 0x5555555bb0a0
#46 GjsContextPrivate::dispose() (this=0x5555555bb0a0) at ../gjs/context.cpp:405
gjs = 0x5555555bb0a0
#47 gjs_context_dispose(GObject*) (object=<optimized out>) at ../gjs/context.cpp:385
gjs = 0x5555555bb0a0
#48 0x00007ffff7d12b14 in g_object_unref (_object=<optimized out>) at ../gobject/gobject.c:3549
weak_locations = 0x0
old_ref = <optimized out>
object = 0x5555555bb200
__func__ = "g_object_unref"
#49 g_object_unref (_object=0x5555555bb200) at ../gobject/gobject.c:3479
object = 0x5555555bb200
__func__ = "g_object_unref"
#50 0x000055555555709d in main(int, char**) (argc=<optimized out>, argv=<optimized out>) at ../gjs/console.cpp:398
context = <optimized out>
error = 0x0
js_context = 0x5555555bb200
coverage = 0x0
script = 0x5555555b66b0 "imports.gi.versions.Gtk = '4.0';\nconst {GLib, GObject, Gio, Gtk} = imports.gi;\nconst ByteArray = imports.byteArray;\n\nGtk.init();\n\nconst Window = GObject.registerClass({\n GTypeName: 'Window',\n Te"...
filename = 0x555555585fa0 "0_XUUU"
program_name = 0x555555585fa0 "0_XUUU"
len = 3813
gjs_argc = <optimized out>
script_argc = <optimized out>
ix = <optimized out>
argv_copy = 0x5555555665f0
argv_copy_addr = <optimized out>
gjs_argv = 0x555555585f40
gjs_argv_addr = 0x555555585f40
script_argv = <optimized out>
env_coverage_output_path = <optimized out>
interactive_mode = <optimized out>
argc_copy = <optimized out>
program_path = {m_ptr = 0x5555555a1dd0 "/home/romain/Code/font-library/test.js"}
env_tracefd = <optimized out>
tracefd = <optimized out>
env_coverage_prefixes = <optimized out>
code = 0
Expected behaviour
Segfault doesn't happen.
The equivalent Python script doesn't segfault:
test.py
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import GLib, GObject, Gtk # noqa
@Gtk.Template(string="""
<interface>
<template class="Window" parent="GtkWindow">
<property name="default-width">600</property>
<property name="default-height">400</property>
<property name="child">
<object class="GtkScrolledWindow">
<property name="vexpand">True</property>
<property name="child">
<object class="GtkListView">
<property name="model">
<object class="GtkNoSelection">
<property name="model" bind-property="model" bind-source="Window"/>
</object>
</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes">
<![CDATA[
<interface>
<template class="GtkListItem">
<property name="child">
<object class="Row">
<binding name="string-object">
<lookup name="item">GtkListItem</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]>
</property>
</object>
</property>
</object>
</property>
</object>
</property>
</template>
</interface>
""")
class Window(Gtk.Window):
__gtype_name__ = "Window"
model = GObject.Property(type=Gtk.StringList)
@Gtk.Template(string="""
<interface>
<template class="Row" parent="GtkBox">
<child>
<object class="GtkLabel">
<binding name="label">
<lookup name="string" type="GtkStringObject">
<lookup name="string-object">Row</lookup>
</lookup>
</binding>
</object>
</child>
</template>
</interface>
""")
class Row(Gtk.Box):
__gtype_name__ = "Row"
string_object = GObject.Property(type=Gtk.StringObject)
loop = GLib.MainLoop.new(None, False)
window = Window(model = Gtk.StringList.new(['test']))
window.connect("close-request", lambda _: loop.quit())
window.present()
loop.run()
Also, not using the custom Row
widget but a Gtk widget like this in the GtkBuilderListItemFactory
doesn't segfault:
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<binding name="label">
<lookup name="string" type="GtkStringObject">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>