Memory management in NPAPI

December 24, 2009 9 Comments by Richard

Introduction

Ever since I started this series of posts on NPAPI and plugins, I have started receiving occasional emails requesting additional help with aspects of NPAPI that are particularly confusing.  With full-time work, FireBreath development, and a 6 month old baby to take care of, I often don’t have as much time as I’d like to give these questions the attention that they deserve.  One that I got today struck me as being a particularly confusing bit for many people, and one that I hope I can answer briefly, so I’m going to give it a shot.  I’m still kinda hoping to get to the point that I can explain smaller bits with shorter posts, which will make it easier for me to post new material more often.

NPObject and NPVariant

In general, there are two datatypes that are used by the browser to pass information.  NPObjects are, for those who haven’t read my previous post on NPAPI, the basic datatype for anything that is scriptable — that is, javascript objects and objects that can talk to javascript.  NPVariant is the datatype that is used to pass parameters and values to and from NPObjects.

As a general rule of thumb: Any time the browser gives you something as a return value, you need to release it using browser API calls.  Any time you return something to the browser as a return value, assume that the browser will release it using browser API calls.

NPObject

struct NPObject {
  NPClass *_class;
  uint32_t referenceCount;
  /*
   * Additional space may be allocated here by types of NPObjects
   */
};

There are three important NPN_ (browser API) functions that you need to understand when using a NPObject:

NPObject creation

It is important to understand that NPN_CreateObject will initialize referenceCount to 1 before returning it.  Thus, if you only plan for it to be used once, you do not need to call NPN_RetainObject on the newly created NPObject.  To do so anyway could prevent the object from ever being released (which could be bad).  A question was ask about the npruntime sample in the gecko source code, and why it calls NPN_RetainObject after NPN_CreateObject.  Here is the function in question:

(from mozilla_central/modules/plugin/sdk/samples/npruntime/plugin.cpp):

NPObject *
CPlugin::GetScriptableObject()
{
    if (!m_pScriptableObject) {
        m_pScriptableObject = NPN_CreateObject(m_pNPInstance, GET_NPOBJECT_CLASS(ScriptablePluginObject));
    }
 
    if (m_pScriptableObject) {
        NPN_RetainObject(m_pScriptableObject);
    }
 
    return m_pScriptableObject;
}

It’s easy to see how you could get confused here.  Why should we call Retain on it if the referenceCount has already been set to 1?  Simply put, the initial referenceCount is to account for the fact that we’re storing the NPObject in this->m_pScriptableObject — we’ll need to call NPN_ReleaseObject in the destructor to release it.  Why do we call Retain, then?  Because we’re returning an NPObject to the browser (in this case, it is only called in response to a NPP_GetValue with NPPVpluginScriptableNPObject as the NPPVariable), and the browser will expect it to have been properly initialized and will call NPN_ReleaseObject when it’s done with it.

Remember the rule of thumb mentioned above:  Any time you return a NPObject as a return value to the browser, the browser will release it when it’s done.  This means it has to have been retained first!  If you weren’t going to keep a copy of the NPObject, then you wouldn’t need to call retain again; just create it and return it each time.  This makes it a little trickier to keep state, unless you have another object that gives the NPObject it’s brains, like is used in FireBreath.

(Firebreath’s NPObject code is in NPJavascriptObject.cpp and NPJavascriptObject.h, and the object it wraps extends JSAPI, with the implementation here.  The JSAPI provides a platform independent abstraction for providing a scriptable object; in other words, you implement your methods and properties in JSAPI and it works everywhere.  There is a good example of a JSAPI object in FBTestPluginAPI.h and FBTestPluginAPI.cpp)

NPVariants

typedef struct _NPVariant {
  NPVariantType type;
  union {
    bool boolValue;
    int32_t intValue;
    double_t doubleValue;
    NPString stringValue;
    NPObject *objectValue;
  } value;
} NPVariant;

The next step in dealing with memory management is to understand how NPVariants work, are allocated, and are released.  NPVariants are used as parameters and return values on NPObject methods.  As you can see from the NPVariant structure above, most NPVariant types are primitives, and thus don’t need any special memory management.  The two types you need to worry about are the NPString and the NPObject.

There are three important NPN_ (browser API) functions that relate to NPStrings:

  • NPN_MemAlloc – Allocates a chunk of memory controlled by the browser and returns a pointer to it (compare to malloc)
  • NPN_MemFree – Frees a chunk of memory controlled by the browser (compare to free)
  • NPN_ReleaseVariantValue – Frees the value in a variant; if the VariantType is NPVariantType_String, calls NPN_MemFree; if it’s NPVariantType_Object, calls NPN_ReleaseObject

Many may wonder, like I did, why we would need to call browser APIs to allocate and free memory, when malloc and free are standard on all C compilers.  The reason is that on many platforms (windows included) each DLL or EXE could have its own memory management routines and its own heap.  Thus if you allocate memory in your plugin DLL and then the browser frees it, or vise versa, you have a problem.

Now, remember our rule of thumb: if it’s returned as a return value, it will be released by the caller using the browser APIs.  When you need to return a string, you allocate it using NPN_MemAlloc, as in the following code snippet from FireBreath:

// We have:
// std::string str as the string to store
// NPVariant *dst as the destination NPVariant
char *outStr = (char*)this->MemAlloc(str.size() + 1);
memcpy(outStr, str.c_str(), str.size() + 1);
dst->type = NPVariantType_String;
dst->value.stringValue.utf8characters = outStr;
dst->value.stringValue.utf8length = str.size();

Then when the browser (triggered by javascript) calls NPN_Invoke, and we use that method to store a NPString in the final parameter (NPVariant *result), the browser will be able to release the memory when it’s done with it.  Similarly, if you call NPN_Invoke, you need to call NPN_ReleaseVariantValue on the returned NPVariant when you’re done.  Also, you are responsible for both creating and releasing the NPVariant array that you pass into NPN_Invoke as arguments.  The same holds true for the NPVariant used in NPN_SetProperty.

The only time you are not responsible for freeing memory is when it is passed in such a way that you don’t have control of it when your function closes.  Similarly, if you have data that is still available after the function that created it is gone, you need to release it.

Conclusion

Well, the biggest thing that I can conclude from this is that I’m not yet capable of keeping things short.  My hope is that this may help someone; I’ve found links to my NPAPI blog posts in a lot of surprising places.  If you know another documentation site that should have a link to this post, please link it!  Also, if you know of another site that explains or illustrates things that need to be clarified from these posts, please post them in the comments!  The primary goal of this blog is to help link together and clarify information that is difficult to find for those getting started in new areas.

Thanks to all who read!