Pointer property on a C class dropped in the child class
System information
- Fedora 29
- gjs 1.54.3 (gjs-1.54.3-2.fc29.x86_64)
- also tested and happening with master code of gjs, commit ec64c542
Bug information
We have a C class with GIOChannel properties which we installed a gpointer:
/**
* GimpPlugIn:read-channel: (type GIOChannel)
*
* The read channel for plug-in communication.
*/
props[PROP_READ_CHANNEL] =
g_param_spec_pointer ("read-channel",
"Read channel",
"The GIOChanel to read from GIMP",
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
In the GIR, with correct annotations, they are seen as their rightful type:
<property name="read-channel"
writable="1"
construct-only="1"
transfer-ownership="none">
<doc xml:space="preserve"
filename="src/gimp/libgimp/gimpplugin.c"
line="93">The read channel for plug-in communication.</doc>
<type name="GLib.IOChannel" c:type="gpointer"/>
</property>
On JavaScript side, we never need to handle these properties. In JS we just create a subclass, we pass the gtype back to C and the object is created in C:
PLUG_IN = g_object_new (plug_in_type,
"read-channel", read_channel,
"write-channel", write_channel,
NULL);
The problem is that while gjs has nothing to do with this property and should just pass it back to the C constructor, it seems to drop the pointer. So we end up with an assertion:
LibGimp:ERROR:/home/jehan/dev/src//gimp/libgimp/../libgimp/gimpplugin.c:128:gimp_plug_in_constructed: assertion failed: (plug_in->priv->read_channel != NULL)
I have also some traces, but not sure how useful these are:
#2 0x00007f4e643f45f0 in gimp_stack_trace_query (prog_name=0x55ae44187110 "/home/jehan/.config/GIMP/2.99/plug-ins/hello-world/hello-world.js") at /home/jehan/dev/src//gimp/libgimpbase/../libgimpbase/gimputils.c:1512
buf = "s\n\000\000\000\000\000\000\006\000\000\000\000\000\000"
#3 0x00007f4e6446337f in gimp_plugin_sigfatal_handler (sig_num=<optimized out>) at /home/jehan/dev/src//gimp/libgimp/../libgimp/gimp.c:1165
sigset = {__val = {0 <repeats 16 times>}}
#4 0x00007f4e673dd070 in <signal handler called> () at /lib64/libpthread.so.0
#5 0x00007f4e6723a57f in raise () at /lib64/libc.so.6
#6 0x00007f4e67224895 in abort () at /lib64/libc.so.6
#7 0x00007f4e68fecb53 in () at /lib64/libglib-2.0.so.0
#8 0x00007f4e690474de in g_assertion_message_expr () at /lib64/libglib-2.0.so.0
#9 0x00007f4e6448ee96 in gimp_plug_in_constructed (object=0x55ae440c2750) at /home/jehan/dev/src//gimp/libgimp/../libgimp/gimpplugin.c:128
plug_in = 0x55ae440c2750
__func__ = "gimp_plug_in_constructed"
#10 0x00007f4e6910770a in () at /lib64/libgobject-2.0.so.0
#11 0x00007f4e691087a5 in g_object_new_with_properties () at /lib64/libgobject-2.0.so.0
#12 0x00007f4e69cf8f62 in ObjectInstance::init_impl(JSContext*, JS::CallArgs const&, JS::MutableHandle<JSObject*>) () at /lib64/libgjs.so.0
#13 0x00007f4e69cf9233 in ObjectBase::init(JSContext*, unsigned int, JS::Value*) () at /lib64/libgjs.so.0
#14 0x00007f4e67b1f564 in () at /lib64/libmozjs-60.so.0
#15 0x00007f4e67b1f95d in () at /lib64/libmozjs-60.so.0
#16 0x00007f4e67e4c579 in JS_CallFunctionValue(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) () at /lib64/libmozjs-60.so.0
#17 0x00007f4e69d11c24 in gjs_call_function_value () at /lib64/libgjs.so.0
#18 0x00007f4e69cf79eb in () at /lib64/libgjs.so.0
#19 0x00007f4e67b202d8 in () at /lib64/libmozjs-60.so.0
#20 0x00007f4e67b203d0 in () at /lib64/libmozjs-60.so.0
#21 0x00007f4e67e4c00a in JS_New(JSContext*, JS::Handle<JSObject*>, JS::HandleValueArray const&) () at /lib64/libmozjs-60.so.0
#22 0x00007f4e69cecd42 in () at /lib64/libgjs.so.0
#23 0x00007f4e69106e8b in () at /lib64/libgobject-2.0.so.0
#24 0x00007f4e69108fde in g_object_new_valist () at /lib64/libgobject-2.0.so.0
#25 0x00007f4e6910933d in g_object_new () at /lib64/libgobject-2.0.so.0
#26 0x00007f4e644639aa in _gimp_main_internal (plug_in_type=, info=0x0, argv=0x55ae44187070, argc=<optimized out>) at /home/jehan/dev/src//gimp/libgimp/../libgimp/gimp.c:569
read_channel = 0x55ae440cf920
write_channel = 0x55ae4413cfa0
basename = <optimized out>
protocol_version = <optimized out>
__func__ = "_gimp_main_internal"
#27 0x00007f4e6930bace in ffi_call_unix64 () at ../src/x86/unix64.S:76
#28 0x00007f4e6930b48f in ffi_call (cif=<optimized out>, fn=<optimized out>, rvalue=<optimized out>, avalue=<optimized out>) at ../src/x86/ffi64.c:525
classes = {X86_64_INTEGER_CLASS, X86_64_NO_CLASS, X86_64_NO_CLASS, X86_64_NO_CLASS}
stack = <optimized out>
argp = <optimized out>
arg_types = <optimized out>
gprcount = <optimized out>
ssecount = <optimized out>
ngpr = 1
nsse = 0
i = <optimized out>
avn = <optimized out>
ret_in_memory = <optimized out>
reg_args = <optimized out>
#29 0x00007f4e69ce88b1 in () at /lib64/libgjs.so.0
#30 0x00007f4e69ce9f2a in () at /lib64/libgjs.so.0
#31 0x00007f4e67b1f794 in () at /lib64/libmozjs-60.so.0
#32 0x00007f4e67b13482 in () at /lib64/libmozjs-60.so.0
#33 0x00007f4e67b1f136 in () at /lib64/libmozjs-60.so.0
#34 0x00007f4e67b20c9f in () at /lib64/libmozjs-60.so.0
#35 0x00007f4e67b20de0 in () at /lib64/libmozjs-60.so.0
#36 0x00007f4e67e2c57e in () at /lib64/libmozjs-60.so.0
#37 0x00007f4e67e2c68b in () at /lib64/libmozjs-60.so.0
#38 0x00007f4e69d1237e in gjs_eval_with_scope () at /lib64/libgjs.so.0
#39 0x00007f4e69d08226 in gjs_context_eval () at /lib64/libgjs.so.0
#40 0x000055ae41e7ac6f in main ()
[Inferior 1 (process 15387) detached]
/home/jehan/.config/GIMP/2.99/plug-ins/hello-world/hello-world.js (pid:15387): [E]xit, show [S]tack trace or [P]roceed: e
GIMP-WARNING: lt-gimp-2.99: gimp_wire_read(): error
Steps to reproduce
I don't have a simpler test than our live code, but I guess it should be reproducible with:
- Make a C class with a gpointer property (let's call it "myprop").
- Make a C function to give only the gtype of the subclass and create a new object in C code:
void
gimp_test(GType subtype)
{
GObject o;
/* HERE add some code to make prop */
o = g_object_new (subtype,
"myprop", prop,
NULL);
}
- Subclass the C class (let's call the subclass
MyClass
). - Call from JS:
Gimp.test(MyClass.$gtype);
Current behaviour
Our code crashs with gjs 1.54.3 in our parent class constructor because we have an assert checking for our property:
g_assert (plug_in->priv->read_channel != NULL);
It would seem that GJS dropped the gpointer property.
Note that I also tested with the master code of gjs, and it still fails, yet differently. With dev code of gjs, the child class constructor fails to create an object at all and returns NULL. We don't even enter the constructed and init of the parent object:
(hello-world.js:16190): GLib-GObject-CRITICAL **: 12:24:31.018: Custom constructor for class GimpMyPlugin returned NULL (which is invalid). Please use GInitable instead.
**
LibGimp:ERROR:/home/jehan/dev/src//gimp/libgimp/../libgimp/gimp.c:574:_gimp_main_internal: assertion failed: (GIMP_IS_PLUG_IN (PLUG_IN))
Expected behaviour
I am not asking for gjs to be able to handle a gpointer (though with proper annotations like here, I guess it could actually be possible?), but at least not to drop it, neither to fail to create the object, when it has nothing to do but to pass the pointer back, untouched, to the parent constructor handled by C.
May be related (or duplicate) to #83.
The proper solution was actually to make it a boxed property. This actually fixed the issue on our side, as gjs was able to handle this type. Still it would be nice to not crash on gpointer properties in gjs, in particular when the JS code is not asked to do anything with that pointer.
Also for the record, the same code (with gpointer) was working just fine with pygobject (Python binding).