Bug 948227 - Add code to warn when the __proto__ setter is called that it's very slow and shouldn't be used. (Don't use it yet, tho, because it requires the second part of bug 948583 to land first. Once that lands, fully enabling this just requires some uncommenting.) r=efaust

--HG--
extra : rebase_source : 87d320edcc99b6ef7df98c2470c78d4085aa4f99
This commit is contained in:
Jeff Walden 2013-12-11 16:04:07 -08:00
parent ffedcc543c
commit cd1afc6984
5 changed files with 37 additions and 13 deletions

View File

@ -574,7 +574,7 @@ struct JSClass {
// with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
// previously allowed, but is now an ES5 violation and thus unsupported.
//
#define JSCLASS_GLOBAL_SLOT_COUNT (3 + JSProto_LIMIT * 3 + 29)
#define JSCLASS_GLOBAL_SLOT_COUNT (3 + JSProto_LIMIT * 3 + 30)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \

View File

@ -556,10 +556,8 @@ obj_watch(JSContext *cx, unsigned argc, Value *vp)
if (!obj)
return false;
#if 0 /* pending addressing Firebug's use of this method */
if (!GlobalObject::warnOnceAboutWatch(cx, obj))
return false;
#endif
if (args.length() <= 1) {
js_ReportMissingArg(cx, args.calleev(), 1);
@ -595,10 +593,8 @@ obj_unwatch(JSContext *cx, unsigned argc, Value *vp)
if (!obj)
return false;
#if 0 /* pending addressing Firebug's use of this method */
if (!GlobalObject::warnOnceAboutWatch(cx, obj))
return false;
#endif
RootedId id(cx);
if (args.length() != 0) {

View File

@ -260,7 +260,7 @@ MSG_DEF(JSMSG_USER_DEFINED_ERROR, 206, 0, JSEXN_ERR, "JS_ReportError was cal
MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 207, 1, JSEXN_TYPEERR, "wrong constructor called for {0}")
MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 208, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 209, 0, JSEXN_TYPEERR, "anonymous generator function returns a value")
MSG_DEF(JSMSG_UNUSED210, 210, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_PROTO_SETTING_SLOW, 210, 0, JSEXN_TYPEERR, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create")
MSG_DEF(JSMSG_IN_AFTER_FOR_NAME, 211, 0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for")
MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 212, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value")
MSG_DEF(JSMSG_UNUSED213, 213, 0, JSEXN_NONE, "")

View File

@ -148,6 +148,14 @@ static bool
ProtoSetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Do this here, rather than in |ProtoSetterImpl|, so even likely-buggy
// use of the __proto__ setter on unacceptable values, where no subsequent
// use occurs on an acceptable value, will trigger a warning.
RootedObject callee(cx, &args.callee());
if (!GlobalObject::warnOnceAboutPrototypeMutation(cx, callee))
return false;
return CallNonGenericMethod(cx, TestProtoThis, ProtoSetterImpl, args);
}
@ -501,18 +509,17 @@ GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx, Handle<GlobalObject*> globa
}
/* static */ bool
GlobalObject::warnOnceAboutWatch(JSContext *cx, HandleObject obj)
GlobalObject::warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber)
{
Rooted<GlobalObject*> global(cx, &obj->global());
HeapSlot &v = global->getSlotRef(WARNED_WATCH_DEPRECATED);
HeapSlot &v = global->getSlotRef(slot);
if (v.isUndefined()) {
// Warn only once per global object.
if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
JSMSG_OBJECT_WATCH_DEPRECATED))
errorNumber))
{
return false;
}
v.init(global, HeapSlot::Slot, WARNED_WATCH_DEPRECATED, BooleanValue(true));
v.init(global, HeapSlot::Slot, slot, BooleanValue(true));
}
return true;
}

View File

@ -105,7 +105,8 @@ class GlobalObject : public JSObject
static const unsigned DATE_TIME_FORMAT_PROTO = NUMBER_FORMAT_PROTO + 1;
static const unsigned REGEXP_STATICS = DATE_TIME_FORMAT_PROTO + 1;
static const unsigned WARNED_WATCH_DEPRECATED = REGEXP_STATICS + 1;
static const unsigned RUNTIME_CODEGEN_ENABLED = WARNED_WATCH_DEPRECATED + 1;
static const unsigned WARNED_PROTO_SETTING_SLOW = WARNED_WATCH_DEPRECATED + 1;
static const unsigned RUNTIME_CODEGEN_ENABLED = WARNED_PROTO_SETTING_SLOW + 1;
static const unsigned DEBUGGERS = RUNTIME_CODEGEN_ENABLED + 1;
static const unsigned INTRINSICS = DEBUGGERS + 1;
static const unsigned FLOAT32X4_TYPE_OBJECT = INTRINSICS + 1;
@ -151,6 +152,13 @@ class GlobalObject : public JSObject
setSlot(INTRINSICS, ObjectValue(*obj));
}
// Emit the specified warning if the given slot in |obj|'s global isn't
// true, then set the slot to true. Thus calling this method warns once
// for each global object it's called on, and every other call does
// nothing.
static bool
warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber);
public:
Value getConstructor(JSProtoKey key) const {
JS_ASSERT(key <= JSProto_LIMIT);
@ -605,7 +613,20 @@ class GlobalObject : public JSObject
// Warn about use of the deprecated watch/unwatch functions in the global
// in which |obj| was created, if no prior warning was given.
static bool warnOnceAboutWatch(JSContext *cx, HandleObject obj);
static bool warnOnceAboutWatch(JSContext *cx, HandleObject obj) {
// Temporarily disabled until we've provided a watch/unwatch workaround for
// debuggers like Firebug (bug 934669).
//return warnOnceAbout(cx, obj, WARNED_WATCH_DEPRECATED, JSMSG_OBJECT_WATCH_DEPRECATED);
return true;
}
// Warn about use of the given __proto__ setter to attempt to mutate an
// object's [[Prototype]], if no prior warning was given.
static bool warnOnceAboutPrototypeMutation(JSContext *cx, HandleObject protoSetter) {
// Temporarily disabled until the second half of bug 948583 lands.
//return warnOnceAbout(cx, protoSetter, WARNED_PROTO_SETTING_SLOW, JSMSG_PROTO_SETTING_SLOW);
return true;
}
static bool getOrCreateEval(JSContext *cx, Handle<GlobalObject*> global,
MutableHandleObject eval);