Closed Bug 470291 Opened 16 years ago Closed 16 years ago

JavaScript delete operator does not invoke npruntime removeProperty on NPObject

Categories

(Core Graveyard :: Plug-ins, defect)

defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: apatrick, Assigned: jaas)

Details

(Keywords: fixed1.9.1)

Attachments

(1 file, 2 obsolete files)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4

In addition to the build identified above, I have checked the latest code in source control and this bug is still present.

The implementation of NPObjWrapper_DelProperty() in modules/plugin/base/src/nsJSNPRuntime.cpp is incomplete.

static JSBool
NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
  NPObject *npobj = GetNPObject(cx, obj);

  if (!npobj || !npobj->_class || !npobj->_class->hasProperty) {
    ThrowJSException(cx, "Bad NPObject as private data!");

    return JS_FALSE;
  }

  if (!npobj->_class->hasProperty(npobj, (NPIdentifier)id)) {
    ThrowJSException(cx, "Trying to remove unsupported property on scriptable "
                     "plugin object!");

    return JS_FALSE;
  }

  return ReportExceptionIfPending(cx);
}

Notice that it does not call npobj->_class->removeProperty. Before checking for the pending exception, it should do something like this:

  JSBool ok = npobj->_class->removeProperty &&
              npobj->_class->removeProperty(npobj, (NPIdentifier)id);
  if (!ok) {
    // throw exception
  }

Compare with the implementation of NPObjWrapper_SetProperty, which calls the setProperty callback or NPObjWrapper_GetProperty which calls the getProperty callback.

Reproducible: Always

Steps to Reproduce:
1. In an npruntime plugin, create an NPObject implementing at least the hasProperty and removeProperty callbacks in its NPClass. The hasProperty function should return true for 'p'.
2. From JavaScript, use the delete operator to remove the property 'p' from the object:

var obj = plugin.getObjectImplementingRemoveProperty();
delete obj.p;
Actual Results:  
The removeProperty callback in not invoked. Therefore the plugin cannot remove the property. The property still exists on the object.

Expected Results:  
The removeProperty callback should be invoked, allowing the plugin to remove the property from the NPObject.

This bug prevents plugins that rely on the removeProperty callback from functioning correctly.
Component: General → Plug-ins
Product: Firefox → Core
QA Contact: general → plugins
Status: UNCONFIRMED → NEW
Ever confirmed: true
Attached patch fix v1.0 (obsolete) — Splinter Review
Assignee: nobody → joshmoz
Attachment #357232 - Flags: superreview?(jst)
Flags: blocking1.9.1?
With regard to fix v1.0, I believe the semantics of JavaScript is to have the delete operator return false if a property cannot be removed rather than throwing an exception. It isn't clear to me whether returning false from NPClass::removeProperty should signify an error or simply that the property does not exist. From my point of view, I would prefer the latter (just return the result of NPClass::removeProperty as the result of the JavaScript delete operator). Likewise, in this case, if NPClass::hasProperty returns false, I would prefer that to simply be returned as the result of the JavaScript delete operator rather than throw an exception.

I think the only cases where an exception should be thrown is if removeProperty (or maybe hasProperty) is null or if the plugin sets an exception. But is there any need to call hasProperty at all?

Of course, my preference may not reflect the best general approach for other npruntime plugins.
Interesting, I don't know what the right thing to do is. Johnny?
Not blocking on this given how rarely delete is used in JS, and nobody apparently noticed before now.
Flags: blocking1.9.1? → blocking1.9.1-
delete is rare in JS? I've seen it being used all over (especially for pseudo-arrays or array-like objects, instead of pop you use delete). Probably doesn't change the blocking- decision though...
Yeah, I'm not saying it's not used, but I've never seen anyone use delete on a *plugin* object. Either way, I think we'll end up fixing this for Firefox 3.1, just sayin' it's not something we'd block the release for.
Comment on attachment 357232 [details] [diff] [review]
fix v1.0

   if (!npobj->_class->hasProperty(npobj, (NPIdentifier)id)) {
     ThrowJSException(cx, "Trying to remove unsupported property on scriptable "
                      "plugin object!");
 
     return JS_FALSE;
   }

Al is right, we shouldn't throw here, we should just return JS_TRUE since that's just how JS works.

+  if (!npobj->_class->removeProperty(npobj, (NPIdentifier)id)) {
+    ThrowJSException(cx, "Removing property failed on scriptable plugin "
+                     "object!");
+
+    return JS_FALSE;
+  }

And here we should just set *rval to BOOLEAN_TO_JSVAL(npobj->_class->removeProperty(...)) so that if removeProperty returns false for some reason, we'll return false to the JS code, and then we'll only throw below if the plugin reported an exception. Fix that, and I'll r+sr...
Attachment #357232 - Flags: superreview?(jst) → superreview-
Attached patch fix v1.1 (obsolete) — Splinter Review
Johnny - I think this is what you're suggesting, though I'm not sure what "*rval" you're referring to. This makes sense to me.
Attachment #357232 - Attachment is obsolete: true
Attachment #357309 - Flags: superreview?(jst)
Comment on attachment 357309 [details] [diff] [review]
fix v1.1

+  if (!npobj->_class->hasProperty(npobj, (NPIdentifier)id))
+    return JS_TRUE;

That's all good...

+  if (!npobj->_class->removeProperty(npobj, (NPIdentifier)id))
     return JS_FALSE;

But that return line need to be replaced by this (i.e. no more early return here):

  *rval = JSVAL_FALSE;

(*rval is the return value that the running *JS* sees from the delete operation. The value returned here in C, is the success code to the JS engine, which is different from the return value seen by the running JS.)

r+sr+a=jst with that changed.
Attachment #357309 - Flags: superreview?(jst)
Attachment #357309 - Flags: superreview+
Attachment #357309 - Flags: review+
Attachment #357309 - Flags: approval1.9.1+
My previous confusion stems from the fact that there is no *rval in the function we're talking about. Perhaps you mean *vp?
Attached patch fix v1.2Splinter Review
Attachment #357309 - Attachment is obsolete: true
Attachment #357352 - Flags: review?(jst)
Attachment #357352 - Flags: superreview+
Attachment #357352 - Flags: review?(jst)
Attachment #357352 - Flags: review+
Attachment #357352 - Flags: approval1.9.1+
Comment on attachment 357352 [details] [diff] [review]
fix v1.2

Yes, *vp was of course what I meant. I was reading JS engine code to verify what I was saying here, and it uses rval instead of vp. Sorry about that, and thanks for fixing!
pushed to mozilla-central

http://hg.mozilla.org/mozilla-central/rev/5c93998e6f75
Status: NEW → RESOLVED
Closed: 16 years ago
Resolution: --- → FIXED
Perhaps I'm not quite following here but could it be fixed like this:

  if (!npobj->_class->hasProperty(npobj, (NPIdentifier)id)) {
    *vp = JSVAL_TRUE; // return true to JS
    return ReportExceptionIfPending(cx); // plugin may have set an exception
  }

  if (npobj->_class->removeProperty(npobj, (NPIdentifier)id))
    *vp = JSVAL_TRUE; // return true to JS
  else
    *vp = JSVAL_FALSE; // return false to JS
 
  // plugin may have set an exception
  return ReportExceptionIfPending(cx);

I think that unless the plugin throws an exception, this function should always set the result returned to the JS language. As fix v1.2 stands, in some cases it will either be a default value or not defined (haven't checked the callers to see which). Also, if hasProperty sets an exception (it would be unusual but it's possible), then it should it not be immediately be thrown into JS, rather than returning successfully?
pushed to mozilla-1.9.1

http://hg.mozilla.org/releases/mozilla-1.9.1/rev/bfe1fd8294b9
Whiteboard: fixed1.9.1
Al - it seems like you're right about *vp not being set consistently, Johnny? If you are right then you should file another bug. Thanks for the feedback.
We can test this now!!!1!!cos(0)!!!
Flags: in-testsuite?
(In reply to comment #16)
> Al - it seems like you're right about *vp not being set consistently, Johnny?
> If you are right then you should file another bug. Thanks for the feedback.

Al, *rval always comes in set to JSVAL_TRUE, so no need to ever set it to that (see http://hg.mozilla.org/mozilla-central/file/3c7610653ad2/js/src/jsobj.cpp#l4178).

But yeah, we should probably report exceptions if hasProperty() ever sets one. Can you please file a new bug on that? Thanks!
I filed a new bug (a minor one) as you requested. See https://bugzilla.mozilla.org/show_bug.cgi?id=474157
Keywords: fixed1.9.1
Whiteboard: fixed1.9.1
Product: Core → Core Graveyard
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: