1

In my NPAPI plugin, some of the objects have an "onEvent" property that is readable and writeable, and which is called on certain events.

What I have in my Javascript code will look like this:

myObject.onEvent = function( event ) {
    console.log("Event: " + event );
}

// if I put this next line, the next call to the 'onEvent' handler will SIGBUS
// when there's no RetainObject() in the getter.
console.log("Event handler : " + myObject.onEvent);

And on the C++ side of the plugin, I have that kind of code:

bool MyPluginObject::getOnEvent(NPIdentifier id, NPVariant *result)
{
    if( _onEvent )
    {
        OBJECT_TO_NPVARIANT( _onEvent, *result);
        NPN_RetainObject( _onEvent ); // needed ???? why??
    }
    else
        VOID_TO_NPVARIANT(*result);

    return true;
}

bool MyPluginObject::setOnEvent( NPIdentifier id, const NPVariant *value )
{
    if ( value && NPVARIANT_IS_OBJECT( *value ) )
    {
        if( _onEvent != NULL )
        {
            // release any previous function retained
            NPN_ReleaseObject( _onEvent );
        }

        _onEvent = NPVARIANT_TO_OBJECT( *value );
        NPN_RetainObject( _onEvent ); // normal retain

        return true;
    }
    return false;
}

void MyPluginObject::onEvent(void)
{
    NPVariant event = [...];

    if ( _onEvent!= NULL )
    {
        NPVariant retVal;
        bool success = NPN_InvokeDefault( _Npp, _onEvent, &event, 1, &retVal );
        if( success )
        {
            NPN_ReleaseVariantValue(&retVal);
        }
    }
}

What's strange is that I've been struggling with a SIGBUS problem for a while, and once I added the NPN_RetainObject() in the getter, as you can see above, everything went fine.

I didn't find in the statement that it is needed in the Mozilla doc, neither in Taxilian's awesome doc about NPAPI.

I don't get it: when the browser requests a property that I've retained, why do I have to retain it a second time?

Should I maybe retain the function when calling InvokeDefault() on it instead? But then, why?? I already stated that I wanted to retain it.

Does getProperty() or InvokeDefault() actually does an NPN_ReleaseObject() without telling me?

Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
Gui13
  • 12,993
  • 17
  • 57
  • 104

1 Answers1

2

You always have to retain object out-parameters with NPAPI, this is not specific to property getters.

In your specific case the object may stay alive anyway, but not in the general case:
Consider returning an object to the caller that you don't plan on keeping alive from your plugin. You have to transfer ownership to the caller and you can't return objects with a retain count of 0.

Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
  • So if I get you completely: that's because when the browser asks for the 'onEvent' property and I give it to him, I silently give him the ownership? Is there somewhere a doc about this? I get your point, but it seems strange to retain the object twise (once on set(), once on get()). – Gui13 Aug 06 '12 at 10:43
  • 1
    Yes, the browser expects the object to be already retained. As mentioned, it might seem strange in this specific case, but you need to look at the general usage of a ref-counting API. All in-parameters need to be retained by the callee if he wants to keep them around (they have to be alive during the call anyway) and all out-parameters have to be retained by the callee: consider the case where you pass an an object to the caller that you don't keep a reference to. – Georg Fritzsche Aug 06 '12 at 11:01
  • I think there is no specific documentation on that, besides side-notes like [the one here](https://developer.mozilla.org/en-US/docs/Gecko_Plugin_API_Reference/Scripting_plugins#Accessing_browser_objects_from_a_plugin). I'll see that i add a section on this when i have the time. – Georg Fritzsche Aug 06 '12 at 11:10