Commit ffffa716 authored by lrn@chromium.org's avatar lrn@chromium.org

Lock the prototype of internal classes.

Prototypes and their properties and methods are locked down to prevent fiddling with their operation, even if the build-in object leaks.

Made some built-in functions only work during bootstrapping.

Review URL: http://codereview.chromium.org/7799027

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9122 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f6c063e1
......@@ -1314,12 +1314,13 @@ function ArrayIsArray(obj) {
// -------------------------------------------------------------------
function SetupArray() {
// Setup non-enumerable constructor property on the Array.prototype
function SetUpArray() {
%CheckIsBootstrapping();
// Set up non-enumerable constructor property on the Array.prototype
// object.
%SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
// Setup non-enumerable functions on the Array object.
// Set up non-enumerable functions on the Array object.
InstallFunctions($Array, DONT_ENUM, $Array(
"isArray", ArrayIsArray
));
......@@ -1337,7 +1338,7 @@ function SetupArray() {
return f;
}
// Setup non-enumerable functions of the Array.prototype object and
// Set up non-enumerable functions of the Array.prototype object and
// set their names.
// Manipulate the length of some of the functions to meet
// expectations set by ECMA-262 or Mozilla.
......@@ -1368,19 +1369,13 @@ function SetupArray() {
%FinishArrayPrototypeSetup($Array.prototype);
// The internal Array prototype doesn't need to be fancy, since it's never
// exposed to user code, so no hidden prototypes or DONT_ENUM attributes
// are necessary.
// The null __proto__ ensures that we never inherit any user created
// getters or setters from, e.g., Object.prototype.
InternalArray.prototype.__proto__ = null;
// Adding only the functions that are actually used, and a toString.
InternalArray.prototype.join = getFunction("join", ArrayJoin);
InternalArray.prototype.pop = getFunction("pop", ArrayPop);
InternalArray.prototype.push = getFunction("push", ArrayPush);
InternalArray.prototype.toString = function() {
return "Internal Array, length " + this.length;
};
// exposed to user code.
// Adding only the functions that are actually used.
SetUpLockedPrototype(InternalArray, $Array(), $Array(
"join", getFunction("join", ArrayJoin),
"pop", getFunction("pop", ArrayPop),
"push", getFunction("push", ArrayPush)
));
}
SetupArray();
SetUpArray();
......@@ -1048,18 +1048,19 @@ function ResetDateCache() {
// -------------------------------------------------------------------
function SetupDate() {
// Setup non-enumerable properties of the Date object itself.
function SetUpDate() {
%CheckIsBootstrapping();
// Set up non-enumerable properties of the Date object itself.
InstallFunctions($Date, DONT_ENUM, $Array(
"UTC", DateUTC,
"parse", DateParse,
"now", DateNow
));
// Setup non-enumerable constructor property of the Date prototype object.
// Set up non-enumerable constructor property of the Date prototype object.
%SetProperty($Date.prototype, "constructor", $Date, DONT_ENUM);
// Setup non-enumerable functions of the Date prototype object and
// Set up non-enumerable functions of the Date prototype object and
// set their names.
InstallFunctionsOnHiddenPrototype($Date.prototype, DONT_ENUM, $Array(
"toString", DateToString,
......@@ -1111,4 +1112,4 @@ function SetupDate() {
));
}
SetupDate();
SetUpDate();
......@@ -337,11 +337,12 @@ function JSONStringify(value, replacer, space) {
return JSONSerialize('', {'': value}, replacer, new InternalArray(), "", gap);
}
function SetupJSON() {
function SetUpJSON() {
%CheckIsBootstrapping();
InstallFunctions($JSON, DONT_ENUM, $Array(
"parse", JSONParse,
"stringify", JSONStringify
));
}
SetupJSON();
SetUpJSON()
......@@ -195,8 +195,9 @@ function MathTan(x) {
// -------------------------------------------------------------------
function SetupMath() {
// Setup math constants.
function SetUpMath() {
%CheckIsBootstrapping();
// Set up math constants.
// ECMA-262, section 15.8.1.1.
%OptimizeObjectForAddingMultipleProperties($Math, 8);
%SetProperty($Math,
......@@ -236,7 +237,7 @@ function SetupMath() {
DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Math);
// Setup non-enumerable functions of the Math object and
// Set up non-enumerable functions of the Math object and
// set their names.
InstallFunctionsOnHiddenPrototype($Math, DONT_ENUM, $Array(
"random", MathRandom,
......@@ -258,7 +259,6 @@ function SetupMath() {
"max", MathMax,
"min", MathMin
));
};
}
SetupMath();
SetUpMath();
This diff is collapsed.
......@@ -405,7 +405,8 @@ var lastMatchInfoOverride = null;
// -------------------------------------------------------------------
function SetupRegExp() {
function SetUpRegExp() {
%CheckIsBootstrapping();
%FunctionSetInstanceClassName($RegExp, 'RegExp');
%FunctionSetPrototype($RegExp, new $Object());
%SetProperty($RegExp.prototype, 'constructor', $RegExp, DONT_ENUM);
......@@ -484,5 +485,4 @@ function SetupRegExp() {
}
}
SetupRegExp();
SetUpRegExp();
......@@ -32,6 +32,7 @@
#include "accessors.h"
#include "api.h"
#include "arguments.h"
#include "bootstrapper.h"
#include "codegen.h"
#include "compilation-cache.h"
#include "compiler.h"
......@@ -2153,6 +2154,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
HandleScope scope(isolate);
ASSERT(args.length() == 2);
......@@ -8256,6 +8258,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
......
......@@ -79,6 +79,7 @@ namespace internal {
F(PreventExtensions, 1, 1)\
\
/* Utilities */ \
F(CheckIsBootstrapping, 0, 1) \
F(GetFunctionDelegate, 1, 1) \
F(GetConstructorDelegate, 1, 1) \
F(NewArgumentsFast, 3, 1) \
......
......@@ -911,50 +911,47 @@ function ReplaceResultBuilder(str) {
this.special_string = str;
}
ReplaceResultBuilder.prototype.__proto__ = null;
ReplaceResultBuilder.prototype.add = function(str) {
str = TO_STRING_INLINE(str);
if (str.length > 0) this.elements.push(str);
}
ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) {
var len = end - start;
if (start < 0 || len <= 0) return;
if (start < 0x80000 && len < 0x800) {
this.elements.push((start << 11) | len);
} else {
// 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
// so -len is a smi.
SetUpLockedPrototype(ReplaceResultBuilder,
$Array("elements", "special_string"), $Array(
"add", function(str) {
str = TO_STRING_INLINE(str);
if (str.length > 0) this.elements.push(str);
},
"addSpecialSlice", function(start, end) {
var len = end - start;
if (start < 0 || len <= 0) return;
if (start < 0x80000 && len < 0x800) {
this.elements.push((start << 11) | len);
} else {
// 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
// so -len is a smi.
var elements = this.elements;
elements.push(-len);
elements.push(start);
}
},
"generate", function() {
var elements = this.elements;
elements.push(-len);
elements.push(start);
return %StringBuilderConcat(elements, elements.length, this.special_string);
}
}
ReplaceResultBuilder.prototype.generate = function() {
var elements = this.elements;
return %StringBuilderConcat(elements, elements.length, this.special_string);
}
));
// -------------------------------------------------------------------
function SetupString() {
// Setup the constructor property on the String prototype object.
function SetUpString() {
%CheckIsBootstrapping();
// Set up the constructor property on the String prototype object.
%SetProperty($String.prototype, "constructor", $String, DONT_ENUM);
// Setup the non-enumerable functions on the String object.
// Set up the non-enumerable functions on the String object.
InstallFunctions($String, DONT_ENUM, $Array(
"fromCharCode", StringFromCharCode
));
// Setup the non-enumerable functions on the String prototype object.
// Set up the non-enumerable functions on the String prototype object.
InstallFunctionsOnHiddenPrototype($String.prototype, DONT_ENUM, $Array(
"valueOf", StringValueOf,
"toString", StringToString,
......@@ -994,5 +991,4 @@ function SetupString() {
));
}
SetupString();
SetUpString();
......@@ -392,8 +392,9 @@ function URIUnescape(str) {
// -------------------------------------------------------------------
function SetupURI() {
// Setup non-enumerable URI functions on the global object and set
function SetUpUri() {
%CheckIsBootstrapping();
// Set up non-enumerable URI functions on the global object and set
// their names.
InstallFunctions(global, DONT_ENUM, $Array(
"escape", URIEscape,
......@@ -405,4 +406,4 @@ function SetupURI() {
));
}
SetupURI();
SetUpUri();
......@@ -75,12 +75,48 @@ function InstallFunctions(object, attributes, functions) {
// functions on String.prototype etc. and then restore the old function
// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
%CheckIsBootstrapping();
var hidden_prototype = new $Object();
%SetHiddenPrototype(object, hidden_prototype);
InstallFunctions(hidden_prototype, attributes, functions);
}
// Prevents changes to the prototype of a built-infunction.
// The "prototype" property of the function object is made non-configurable,
// and the prototype object is made non-extensible. The latter prevents
// changing the __proto__ property.
function SetUpLockedPrototype(constructor, fields, methods) {
%CheckIsBootstrapping();
var prototype = constructor.prototype;
// Install functions first, because this function is used to initialize
// PropertyDescriptor itself.
var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
if (property_count >= 4) {
%OptimizeObjectForAddingMultipleProperties(prototype, property_count);
}
if (fields) {
for (var i = 0; i < fields.length; i++) {
%SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
}
}
for (var i = 0; i < methods.length; i += 2) {
var key = methods[i];
var f = methods[i + 1];
%SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
%SetNativeFlag(f);
}
prototype.__proto__ = null;
%PreventExtensions(prototype);
%ToFastProperties(prototype);
var desc = GetOwnProperty(constructor, "prototype");
desc.setWritable(false);
desc.setConfigurable(false);
DefineOwnProperty(constructor, "prototype", desc, false);
}
// ----------------------------------------------------------------------------
......@@ -171,8 +207,9 @@ function GlobalEval(x) {
// ----------------------------------------------------------------------------
function SetupGlobal() {
// Set up global object.
function SetUpGlobal() {
%CheckIsBootstrapping();
// ECMA 262 - 15.1.1.1.
%SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
......@@ -182,7 +219,7 @@ function SetupGlobal() {
// ECMA-262 - 15.1.1.3.
%SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
// Setup non-enumerable function on the global object.
// Set up non-enumerable function on the global object.
InstallFunctions(global, DONT_ENUM, $Array(
"isNaN", GlobalIsNaN,
"isFinite", GlobalIsFinite,
......@@ -192,8 +229,7 @@ function SetupGlobal() {
));
}
SetupGlobal();
SetUpGlobal();
// ----------------------------------------------------------------------------
// Boolean (first part of definition)
......@@ -490,106 +526,83 @@ function PropertyDescriptor() {
this.hasSetter_ = false;
}
PropertyDescriptor.prototype.__proto__ = null;
PropertyDescriptor.prototype.toString = function() {
return "[object PropertyDescriptor]";
};
PropertyDescriptor.prototype.setValue = function(value) {
this.value_ = value;
this.hasValue_ = true;
}
PropertyDescriptor.prototype.getValue = function() {
return this.value_;
}
PropertyDescriptor.prototype.hasValue = function() {
return this.hasValue_;
}
PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
this.enumerable_ = enumerable;
this.hasEnumerable_ = true;
}
PropertyDescriptor.prototype.isEnumerable = function () {
return this.enumerable_;
}
PropertyDescriptor.prototype.hasEnumerable = function() {
return this.hasEnumerable_;
}
PropertyDescriptor.prototype.setWritable = function(writable) {
this.writable_ = writable;
this.hasWritable_ = true;
}
PropertyDescriptor.prototype.isWritable = function() {
return this.writable_;
}
PropertyDescriptor.prototype.hasWritable = function() {
return this.hasWritable_;
}
PropertyDescriptor.prototype.setConfigurable = function(configurable) {
this.configurable_ = configurable;
this.hasConfigurable_ = true;
}
PropertyDescriptor.prototype.hasConfigurable = function() {
return this.hasConfigurable_;
}
PropertyDescriptor.prototype.isConfigurable = function() {
return this.configurable_;
}
PropertyDescriptor.prototype.setGet = function(get) {
this.get_ = get;
this.hasGetter_ = true;
}
PropertyDescriptor.prototype.getGet = function() {
return this.get_;
}
PropertyDescriptor.prototype.hasGetter = function() {
return this.hasGetter_;
}
PropertyDescriptor.prototype.setSet = function(set) {
this.set_ = set;
this.hasSetter_ = true;
}
PropertyDescriptor.prototype.getSet = function() {
return this.set_;
}
PropertyDescriptor.prototype.hasSetter = function() {
return this.hasSetter_;
}
SetUpLockedPrototype(PropertyDescriptor, $Array(
"value_",
"hasValue_",
"writable_",
"hasWritable_",
"enumerable_",
"hasEnumerable_",
"configurable_",
"hasConfigurable_",
"get_",
"hasGetter_",
"set_",
"hasSetter_"
), $Array(
"toString", function() {
return "[object PropertyDescriptor]";
},
"setValue", function(value) {
this.value_ = value;
this.hasValue_ = true;
},
"getValue", function() {
return this.value_;
},
"hasValue", function() {
return this.hasValue_;
},
"setEnumerable", function(enumerable) {
this.enumerable_ = enumerable;
this.hasEnumerable_ = true;
},
"isEnumerable", function () {
return this.enumerable_;
},
"hasEnumerable", function() {
return this.hasEnumerable_;
},
"setWritable", function(writable) {
this.writable_ = writable;
this.hasWritable_ = true;
},
"isWritable", function() {
return this.writable_;
},
"hasWritable", function() {
return this.hasWritable_;
},
"setConfigurable", function(configurable) {
this.configurable_ = configurable;
this.hasConfigurable_ = true;
},
"hasConfigurable", function() {
return this.hasConfigurable_;
},
"isConfigurable", function() {
return this.configurable_;
},
"setGet", function(get) {
this.get_ = get;
this.hasGetter_ = true;
},
"getGet", function() {
return this.get_;
},
"hasGetter", function() {
return this.hasGetter_;
},
"setSet", function(set) {
this.set_ = set;
this.hasSetter_ = true;
},
"getSet", function() {
return this.set_;
},
"hasSetter", function() {
return this.hasSetter_;
}));
// Converts an array returned from Runtime_GetOwnProperty to an actual
......@@ -1177,10 +1190,11 @@ function ObjectIsExtensible(obj) {
%SetExpectedNumberOfProperties($Object, 4);
// ----------------------------------------------------------------------------
// Object
function SetupObject() {
// Setup non-enumerable functions on the Object.prototype object.
function SetUpObject() {
%CheckIsBootstrapping();
// Set Up non-enumerable functions on the Object.prototype object.
InstallFunctions($Object.prototype, DONT_ENUM, $Array(
"toString", ObjectToString,
"toLocaleString", ObjectToLocaleString,
......@@ -1210,8 +1224,7 @@ function SetupObject() {
));
}
SetupObject();
SetUpObject();
// ----------------------------------------------------------------------------
// Boolean
......@@ -1242,14 +1255,16 @@ function BooleanValueOf() {
// ----------------------------------------------------------------------------
function SetupBoolean() {
function SetUpBoolean () {
%CheckIsBootstrapping();
InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
"toString", BooleanToString,
"valueOf", BooleanValueOf
));
}
SetupBoolean();
SetUpBoolean();
// ----------------------------------------------------------------------------
// Number
......@@ -1363,9 +1378,10 @@ function NumberToPrecision(precision) {
// ----------------------------------------------------------------------------
function SetupNumber() {
function SetUpNumber() {
%CheckIsBootstrapping();
%OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
// Setup the constructor property on the Number prototype object.
// Set up the constructor property on the Number prototype object.
%SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
%OptimizeObjectForAddingMultipleProperties($Number, 5);
......@@ -1394,7 +1410,7 @@ function SetupNumber() {
DONT_ENUM | DONT_DELETE | READ_ONLY);
%ToFastProperties($Number);
// Setup non-enumerable functions on the Number prototype object.
// Set up non-enumerable functions on the Number prototype object.
InstallFunctions($Number.prototype, DONT_ENUM, $Array(
"toString", NumberToString,
"toLocaleString", NumberToLocaleString,
......@@ -1405,7 +1421,7 @@ function SetupNumber() {
));
}
SetupNumber();
SetUpNumber();
// ----------------------------------------------------------------------------
......@@ -1534,11 +1550,12 @@ function NewFunction(arg1) { // length == 1
// ----------------------------------------------------------------------------
function SetupFunction() {
function SetUpFunction() {
%CheckIsBootstrapping();
InstallFunctions($Function.prototype, DONT_ENUM, $Array(
"bind", FunctionBind,
"toString", FunctionToString
));
}
SetupFunction();
SetUpFunction();
......@@ -80,7 +80,8 @@ function WeakMapDelete(key) {
// -------------------------------------------------------------------
function SetupWeakMap() {
(function () {
%CheckIsBootstrapping();
// Set up the WeakMap constructor function.
%SetCode($WeakMap, WeakMapConstructor);
......@@ -97,7 +98,4 @@ function SetupWeakMap() {
"has", WeakMapHas,
"delete", WeakMapDelete
));
}
SetupWeakMap();
})();
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-natives-as=builtins
// Checks that all function properties of the builtin object are neither
// writable nor configurable. Also, theose functions that are actually
// constructors (recognized by having properties on their .prototype object),
// have only unconfigurable properties on the prototype, and the methods
// are also non-writable.
var names = Object.getOwnPropertyNames(builtins);
function isFunction(obj) {
return typeof obj == "function";
}
function checkConstructor(func, name) {
// A constructor is a function with a prototype and properties on the
// prototype object besides "constructor";
if (name.charAt(0) == "$") return;
if (typeof func.prototype != "object") return;
var propNames = Object.getOwnPropertyNames(func.prototype);
if (propNames.length == 0 ||
(propNames.length == 1 && propNames[0] == "constructor")) {
// Not a constructor.
return;
}
var proto_desc = Object.getOwnPropertyDescriptor(func, "prototype");
assertTrue(proto_desc.hasOwnProperty("value"), name);
assertFalse(proto_desc.writable, name);
assertFalse(proto_desc.configurable, name);
var prototype = proto_desc.value;
assertEquals(null, prototype.__proto__, name);
assertFalse(Object.isExtensible(prototype), name);
for (var i = 0; i < propNames.length; i++) {
var propName = propNames[i];
if (propName == "constructor") continue;
var testName = name + "-" + propName;
var propDesc = Object.getOwnPropertyDescriptor(prototype, propName);
assertTrue(propDesc.hasOwnProperty("value"), testName);
assertFalse(propDesc.configurable, testName);
if (isFunction(propDesc.value)) {
assertFalse(propDesc.writable, testName);
}
}
}
for (var i = 0; i < names.length; i++) {
var name = names[i];
var desc = Object.getOwnPropertyDescriptor(builtins, name);
assertTrue(desc.hasOwnProperty("value"));
var value = desc.value;
if (isFunction(value)) {
assertFalse(desc.writable, name);
assertFalse(desc.configurable, name);
checkConstructor(value, name);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment