Skip to content

Add regression tests for GObject vfuncs

Jason Hicks requested to merge jaszhix/gjs:allow-checking-vfunc-props into master

I've been running into what I think is a regression since 5aa46c2e. It's now not possible to check the existence of a vfunc on a prototype without doing it from inside its object instance. This is occurring on some objects that only partially (?) define a vfunc. An example would be St.DrawingArea - it has a repaint signal and a vfunc that can be overridden in JS, but it would only function as a signal. There's not actually a vfunc to override, but the "space" is available for one - at least that is how I'm understanding it from the behavior.

When this does occur it causes a crash, all that is seen is

00:49:53.762: Script terminated with an uncatchable exception

Execution of main.js threw exception: Script terminated with an uncatchable exception

An example use case would be dynamically overriding a vfunc.

const parentFunc = parent.prototype[prop];
if (parentFunc) {
    Object.defineProperty(Class.prototype, prop, {
        value() {
            let args = Array.prototype.slice.call(arguments);
            this.callbacks[key](...args);
            return parentFunc.call(this, ...args);
        }
    });
} else {
    Object.defineProperty(Class.prototype, prop, {
        value() {
            let args = Array.prototype.slice.call(arguments);
            return this.callbacks[key](...args);
        }
    });
}

This code would cause the process to exit with no actionable error, or a gdb trace. It would be possible to do this check in the instance, but since some vfuncs can be called very frequently, it is better for performance to be able to do these checks once when setting up the class.

Another override quirk this fixes is allowing vfuncs with property names and anonymous function names.

Class.prototype.vfunc_get_preferred_height = function(forHeight) {
    if (!this.node) this.node = this.get_theme_node();
    let [min, nat] = this.callbacks.get_preferred_height(forHeight);
    return this.node.adjust_preferred_height(min, nat);
};

This code fails, but didn't on GJS 1.52. Changing the first line to

Class.prototype.vfunc_get_preferred_height = function vfunc_get_preferred_height(forHeight) {

does work, but then if you were passing the property as a variable you would need to use Object.defineProperty or use the function constructor.

Edited by Jason Hicks

Merge request reports