Make sure builtin functions don't rely on __proto__.

This makes sure that none of the builtin functions rely on the __proto__
accessor which can now be monkey-patched by applications. Instead use a
separate %SetPrototype() intrinsic or object literals to do the job.

R=rossberg@chromium.org

Review URL: https://codereview.chromium.org/12385082

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13815 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mstarzinger@chromium.org 2013-03-04 16:05:12 +00:00
parent 1630954005
commit 0ca02ee48d
14 changed files with 62 additions and 21 deletions

View File

@ -90,7 +90,7 @@ function InstantiateFunction(data, name) {
// internal ToBoolean doesn't handle that!
if (!(typeof parent === 'undefined')) {
var parent_fun = Instantiate(parent);
fun.prototype.__proto__ = parent_fun.prototype;
%SetPrototype(fun.prototype, parent_fun.prototype);
}
ConfigureTemplateInstance(fun, data);
} catch (e) {

View File

@ -1646,8 +1646,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
break;
}
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
// Duplicate receiver on stack.
__ ldr(r0, MemOperand(sp));
__ push(r0);
@ -1661,6 +1659,18 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Drop(3);
}
break;
case ObjectLiteral::Property::PROTOTYPE:
// Duplicate receiver on stack.
__ ldr(r0, MemOperand(sp));
__ push(r0);
VisitForStackValue(value);
if (property->emit_store()) {
__ CallRuntime(Runtime::kSetPrototype, 2);
} else {
__ Drop(2);
}
break;
case ObjectLiteral::Property::GETTER:
accessor_table.lookup(key)->second->getter = value;
break;

View File

@ -885,7 +885,7 @@ function ArraySort(comparefn) {
// of a prototype property.
var CopyFromPrototype = function CopyFromPrototype(obj, length) {
var max = 0;
for (var proto = obj.__proto__; proto; proto = proto.__proto__) {
for (var proto = %GetPrototype(obj); proto; proto = %GetPrototype(proto)) {
var indices = %GetArrayKeys(proto, length);
if (indices.length > 0) {
if (indices[0] == -1) {
@ -916,7 +916,7 @@ function ArraySort(comparefn) {
// where a prototype of obj has an element. I.e., shadow all prototype
// elements in that range.
var ShadowPrototypeElements = function(obj, from, to) {
for (var proto = obj.__proto__; proto; proto = proto.__proto__) {
for (var proto = %GetPrototype(obj); proto; proto = %GetPrototype(proto)) {
var indices = %GetArrayKeys(proto, to);
if (indices.length > 0) {
if (indices[0] == -1) {
@ -986,7 +986,7 @@ function ArraySort(comparefn) {
}
for (i = length - num_holes; i < length; i++) {
// For compatability with Webkit, do not expose elements in the prototype.
if (i in obj.__proto__) {
if (i in %GetPrototype(obj)) {
obj[i] = void 0;
} else {
delete obj[i];

View File

@ -71,7 +71,7 @@ function GetCompletions(global, last, full) {
result.push(name);
}
}
current = ToInspectableObject(current.__proto__);
current = ToInspectableObject(Object.getPrototypeOf(current));
}
return result;
}

View File

@ -1601,8 +1601,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
break;
}
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
__ push(Operand(esp, 0)); // Duplicate receiver.
VisitForStackValue(key);
VisitForStackValue(value);
@ -1613,6 +1611,15 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Drop(3);
}
break;
case ObjectLiteral::Property::PROTOTYPE:
__ push(Operand(esp, 0)); // Duplicate receiver.
VisitForStackValue(value);
if (property->emit_store()) {
__ CallRuntime(Runtime::kSetPrototype, 2);
} else {
__ Drop(2);
}
break;
case ObjectLiteral::Property::GETTER:
accessor_table.lookup(key)->second->getter = value;
break;

View File

@ -37,7 +37,7 @@ var $abs = MathAbs;
function MathConstructor() {}
%FunctionSetInstanceClassName(MathConstructor, 'Math');
var $Math = new MathConstructor();
$Math.__proto__ = $Object.prototype;
%SetPrototype($Math, $Object.prototype);
%SetProperty(global, "Math", $Math, DONT_ENUM);
// ECMA 262 - 15.8.2.1

View File

@ -1208,7 +1208,7 @@ var cyclic_error_marker = new $Object();
function GetPropertyWithoutInvokingMonkeyGetters(error, name) {
// Climb the prototype chain until we find the holder.
while (error && !%HasLocalProperty(error, name)) {
error = error.__proto__;
error = %GetPrototype(error);
}
if (error === null) return void 0;
if (!IS_OBJECT(error)) return error[name];

View File

@ -1654,8 +1654,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
break;
}
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
// Duplicate receiver on stack.
__ lw(a0, MemOperand(sp));
__ push(a0);
@ -1669,6 +1667,17 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Drop(3);
}
break;
case ObjectLiteral::Property::PROTOTYPE:
// Duplicate receiver on stack.
__ lw(a0, MemOperand(sp));
__ push(a0);
VisitForStackValue(value);
if (property->emit_store()) {
__ CallRuntime(Runtime::kSetPrototype, 2);
} else {
__ Drop(2);
}
break;
case ObjectLiteral::Property::GETTER:
accessor_table.lookup(key)->second->getter = value;
break;

View File

@ -4872,7 +4872,7 @@ class Map: public HeapObject {
inline bool function_with_prototype();
// Tells whether the instance with this map should be ignored by the
// __proto__ accessor.
// Object.getPrototypeOf() function and the __proto__ accessor.
inline void set_is_hidden_prototype() {
set_bit_field(bit_field() | (1 << kIsHiddenPrototype));
}

View File

@ -77,8 +77,7 @@ function DerivedConstructTrap(callTrap) {
return function() {
var proto = this.prototype
if (!IS_SPEC_OBJECT(proto)) proto = $Object.prototype
var obj = new $Object()
obj.__proto__ = proto
var obj = { __proto__: proto };
var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength());
return IS_SPEC_OBJECT(result) ? result : obj
}

View File

@ -975,6 +975,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) {
NoHandleAllocation ha(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
CONVERT_ARG_CHECKED(Object, prototype, 1);
return input_obj->SetPrototype(prototype, true);
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
NoHandleAllocation ha(isolate);
ASSERT(args.length() == 2);

View File

@ -67,6 +67,7 @@ namespace internal {
F(GetDefaultReceiver, 1, 1) \
\
F(GetPrototype, 1, 1) \
F(SetPrototype, 2, 1) \
F(IsInPrototypeChain, 2, 1) \
\
F(GetOwnProperty, 2, 1) \

View File

@ -94,7 +94,7 @@ function SetUpLockedPrototype(constructor, fields, methods) {
%SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
%SetNativeFlag(f);
}
prototype.__proto__ = null;
%SetPrototype(prototype, null);
%ToFastProperties(prototype);
}
@ -1074,8 +1074,7 @@ function ObjectCreate(proto, properties) {
if (!IS_SPEC_OBJECT(proto) && proto !== null) {
throw MakeTypeError("proto_object_or_null", [proto]);
}
var obj = new $Object();
obj.__proto__ = proto;
var obj = { __proto__: proto };
if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
return obj;
}

View File

@ -1626,8 +1626,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
break;
}
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
__ push(Operand(rsp, 0)); // Duplicate receiver.
VisitForStackValue(key);
VisitForStackValue(value);
@ -1638,6 +1636,15 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Drop(3);
}
break;
case ObjectLiteral::Property::PROTOTYPE:
__ push(Operand(rsp, 0)); // Duplicate receiver.
VisitForStackValue(value);
if (property->emit_store()) {
__ CallRuntime(Runtime::kSetPrototype, 2);
} else {
__ Drop(2);
}
break;
case ObjectLiteral::Property::GETTER:
accessor_table.lookup(key)->second->getter = value;
break;