Bug 961494 - Adjust an assertion to properly handle objects with built-in properties stored in reserved slots, where the last property of such an object may use a reserved slot that's not the last reserved slot. r=jorendorff, f=bhackett

This commit is contained in:
Jeff Walden 2014-02-12 13:21:16 -08:00
parent d1872d42a6
commit 03fcb98c2b
4 changed files with 88 additions and 2 deletions

View File

@ -29,6 +29,7 @@ UNIFIED_SOURCES += [
'testException.cpp', 'testException.cpp',
'testExternalStrings.cpp', 'testExternalStrings.cpp',
'testFindSCCs.cpp', 'testFindSCCs.cpp',
'testFreshGlobalEvalRedefinition.cpp',
'testFuncCallback.cpp', 'testFuncCallback.cpp',
'testFunctionProperties.cpp', 'testFunctionProperties.cpp',
'testGCExactRooting.cpp', 'testGCExactRooting.cpp',

View File

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsapi-tests/tests.h"
static bool
GlobalEnumerate(JSContext *cx, JS::Handle<JSObject*> obj)
{
return JS_EnumerateStandardClasses(cx, obj);
}
static bool
GlobalResolve(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id)
{
bool resolved = false;
return JS_ResolveStandardClass(cx, obj, id, &resolved);
}
BEGIN_TEST(testRedefineGlobalEval)
{
static const JSClass cls = {
"global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
GlobalEnumerate, GlobalResolve, JS_ConvertStub
};
/* Create the global object. */
JS::CompartmentOptions options;
options.setVersion(JSVERSION_LATEST);
JS::Rooted<JSObject*> g(cx, JS_NewGlobalObject(cx, &cls, nullptr, JS::FireOnNewGlobalHook, options));
if (!g)
return false;
JSAutoCompartment ac(cx, g);
JS::Rooted<JS::Value> v(cx);
CHECK(JS_GetProperty(cx, g, "Object", &v));
static const char data[] = "Object.defineProperty(this, 'eval', { configurable: false });";
CHECK(JS_EvaluateScript(cx, g, data, mozilla::ArrayLength(data) - 1, __FILE__, __LINE__, v.address()));
return true;
}
END_TEST(testRedefineGlobalEval)

View File

@ -0,0 +1,28 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var gTestfile = "error-expando-reconfigure.js"
//-----------------------------------------------------------------------------
var BUGNUMBER = 961494;
var summary =
"Reconfiguring the first expando property added to an Error object " +
"shouldn't assert";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
var err = new Error(); // no message argument => no err.message property
err.expando = 17;
Object.defineProperty(err, "expando", { configurable: false });
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

View File

@ -352,10 +352,20 @@ JSObject::getChildPropertyOnDictionary(ThreadSafeContext *cx, JS::HandleObject o
return nullptr; return nullptr;
child.setSlot(slot); child.setSlot(slot);
} else { } else {
/* Slots can only be allocated out of order on objects in dictionary mode. */ /*
* Slots can only be allocated out of order on objects in
* dictionary mode. Otherwise the child's slot must be after the
* parent's slot (if it has one), because slot number determines
* slot span for objects with that shape. Usually child slot
* *immediately* follows parent slot, but there may be a slot gap
* when the object uses some -- but not all -- of its reserved
* slots to store properties.
*/
JS_ASSERT(obj->inDictionaryMode() || JS_ASSERT(obj->inDictionaryMode() ||
parent->hasMissingSlot() || parent->hasMissingSlot() ||
child.slot() == parent->maybeSlot() + 1); child.slot() == parent->maybeSlot() + 1 ||
(parent->maybeSlot() + 1 < JSSLOT_FREE(obj->getClass()) &&
child.slot() == JSSLOT_FREE(obj->getClass())));
} }
} }