зеркало из https://github.com/mozilla/gecko-dev.git
Bug 679509 - Make sure convert hooks in plugin code always return a primitive value. r=mrbkap, r=luke, r=jst
--HG-- extra : rebase_source : adf240c22329d3461a2c939d11798247a98b867f
This commit is contained in:
Родитель
0a9e618b59
Коммит
399df285d6
|
@ -1684,15 +1684,39 @@ NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
}
|
||||
|
||||
static JSBool
|
||||
NPObjWrapper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
NPObjWrapper_Convert(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
|
||||
{
|
||||
// The sole reason we implement this hook is to prevent the JS
|
||||
// engine from calling valueOf() on NPObject's. Some NPObject's may
|
||||
// actually implement a method named valueOf, but it's unlikely to
|
||||
// behave as the JS engine expects it to. IOW, this is an empty hook
|
||||
// that overrides what the default hook does.
|
||||
JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
|
||||
|
||||
return JS_TRUE;
|
||||
// Plugins do not simply use JS_ConvertStub, and the default [[DefaultValue]]
|
||||
// behavior, because that behavior involves calling toString or valueOf on
|
||||
// objects which weren't designed to accommodate this. Usually this wouldn't
|
||||
// be a problem, because the absence of either property, or the presence of
|
||||
// either property with a value that isn't callable, will cause that property
|
||||
// to simply be ignored. But there is a problem in one specific case: Java,
|
||||
// specifically java.lang.Integer. The Integer class has static valueOf
|
||||
// methods, none of which are nullary, so the JS-reflected method will behave
|
||||
// poorly when called with no arguments. We work around this problem by
|
||||
// giving plugins a [[DefaultValue]] which uses only toString and not valueOf.
|
||||
|
||||
jsval v = JSVAL_VOID;
|
||||
if (!JS_GetProperty(cx, obj, "toString", &v))
|
||||
return false;
|
||||
if (!JSVAL_IS_PRIMITIVE(v) && JS_ObjectIsCallable(cx, JSVAL_TO_OBJECT(v))) {
|
||||
if (!JS_CallFunctionValue(cx, obj, v, 0, NULL, vp))
|
||||
return false;
|
||||
if (JSVAL_IS_PRIMITIVE(*vp))
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
|
||||
JS_GET_CLASS(cx, obj)->name,
|
||||
hint == JSTYPE_VOID
|
||||
? "primitive type"
|
||||
: hint == JSTYPE_NUMBER
|
||||
? "number"
|
||||
: "string");
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2192,6 +2216,11 @@ NPObjectMember_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
|||
case JSTYPE_VOID:
|
||||
case JSTYPE_STRING:
|
||||
case JSTYPE_NUMBER:
|
||||
*vp = memberPrivate->fieldValue;
|
||||
if (!JSVAL_IS_PRIMITIVE(*vp)) {
|
||||
return JS_DefaultValue(cx, JSVAL_TO_OBJECT(*vp), type, vp);
|
||||
}
|
||||
return JS_TRUE;
|
||||
case JSTYPE_BOOLEAN:
|
||||
case JSTYPE_OBJECT:
|
||||
*vp = memberPrivate->fieldValue;
|
||||
|
|
|
@ -46,6 +46,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
_MOCHITEST_FILES = \
|
||||
utils.js \
|
||||
test_defaultValue.html \
|
||||
test_getauthenticationinfo.html \
|
||||
test_npobject_getters.html \
|
||||
test_npruntime_npnevaluate.html \
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>NPObject [[DefaultValue]] implementation</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
|
||||
<body onload="run()">
|
||||
|
||||
<embed id="plugin" type="application/x-test" wmode="window"></embed>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function run() {
|
||||
var plugin = document.getElementById("plugin");
|
||||
var pluginProto = Object.getPrototypeOf(plugin);
|
||||
|
||||
plugin.propertyAndMethod = {};
|
||||
plugin.propertyAndMethod + "baz";
|
||||
ok(true, "|plugin.propertyAndMethod + \"baz\"| shouldn't assert");
|
||||
pluginProto.propertyAndMethod = {};
|
||||
pluginProto.propertyAndMethod + "quux";
|
||||
ok(true, "|pluginProto.propertyAndMethod + \"quux\"| shouldn't assert");
|
||||
|
||||
plugin + "foo";
|
||||
ok(true, "|plugin + \"foo\"| shouldn't assert");
|
||||
pluginProto + "bar";
|
||||
ok(true, "|pluginProto + \"bar\"| shouldn't assert");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -2926,6 +2926,15 @@ JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
JS_ASSERT(obj != NULL);
|
||||
JS_ASSERT(hint == JSTYPE_VOID || hint == JSTYPE_STRING || hint == JSTYPE_NUMBER);
|
||||
return obj->defaultValue(cx, hint, vp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
|
|
|
@ -3125,6 +3125,15 @@ JS_IdToValue(JSContext *cx, jsid id, jsval *vp);
|
|||
#define JSRESOLVE_CLASSNAME 0x10 /* class name used when constructing */
|
||||
#define JSRESOLVE_WITH 0x20 /* resolve inside a with statement */
|
||||
|
||||
/*
|
||||
* Invoke the [[DefaultValue]] hook (see ES5 8.6.2) with the provided hint on
|
||||
* the specified object, computing a primitive default value for the object.
|
||||
* The hint must be JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_VOID (no hint). On
|
||||
* success the resulting value is stored in *vp.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче