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! // internal ToBoolean doesn't handle that!
if (!(typeof parent === 'undefined')) { if (!(typeof parent === 'undefined')) {
var parent_fun = Instantiate(parent); var parent_fun = Instantiate(parent);
fun.prototype.__proto__ = parent_fun.prototype; %SetPrototype(fun.prototype, parent_fun.prototype);
} }
ConfigureTemplateInstance(fun, data); ConfigureTemplateInstance(fun, data);
} catch (e) { } catch (e) {

View File

@ -1646,8 +1646,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
} }
break; break;
} }
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
// Duplicate receiver on stack. // Duplicate receiver on stack.
__ ldr(r0, MemOperand(sp)); __ ldr(r0, MemOperand(sp));
__ push(r0); __ push(r0);
@ -1661,6 +1659,18 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Drop(3); __ Drop(3);
} }
break; 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: case ObjectLiteral::Property::GETTER:
accessor_table.lookup(key)->second->getter = value; accessor_table.lookup(key)->second->getter = value;
break; break;

View File

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

View File

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

View File

@ -1601,8 +1601,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
} }
break; break;
} }
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
__ push(Operand(esp, 0)); // Duplicate receiver. __ push(Operand(esp, 0)); // Duplicate receiver.
VisitForStackValue(key); VisitForStackValue(key);
VisitForStackValue(value); VisitForStackValue(value);
@ -1613,6 +1611,15 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Drop(3); __ Drop(3);
} }
break; 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: case ObjectLiteral::Property::GETTER:
accessor_table.lookup(key)->second->getter = value; accessor_table.lookup(key)->second->getter = value;
break; break;

View File

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

View File

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

View File

@ -1654,8 +1654,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
} }
break; break;
} }
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
// Duplicate receiver on stack. // Duplicate receiver on stack.
__ lw(a0, MemOperand(sp)); __ lw(a0, MemOperand(sp));
__ push(a0); __ push(a0);
@ -1669,6 +1667,17 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Drop(3); __ Drop(3);
} }
break; 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: case ObjectLiteral::Property::GETTER:
accessor_table.lookup(key)->second->getter = value; accessor_table.lookup(key)->second->getter = value;
break; break;

View File

@ -4872,7 +4872,7 @@ class Map: public HeapObject {
inline bool function_with_prototype(); inline bool function_with_prototype();
// Tells whether the instance with this map should be ignored by the // 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() { inline void set_is_hidden_prototype() {
set_bit_field(bit_field() | (1 << kIsHiddenPrototype)); set_bit_field(bit_field() | (1 << kIsHiddenPrototype));
} }

View File

@ -77,8 +77,7 @@ function DerivedConstructTrap(callTrap) {
return function() { return function() {
var proto = this.prototype var proto = this.prototype
if (!IS_SPEC_OBJECT(proto)) proto = $Object.prototype if (!IS_SPEC_OBJECT(proto)) proto = $Object.prototype
var obj = new $Object() var obj = { __proto__: proto };
obj.__proto__ = proto
var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength()); var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength());
return IS_SPEC_OBJECT(result) ? result : obj 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) { RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
NoHandleAllocation ha(isolate); NoHandleAllocation ha(isolate);
ASSERT(args.length() == 2); ASSERT(args.length() == 2);

View File

@ -67,6 +67,7 @@ namespace internal {
F(GetDefaultReceiver, 1, 1) \ F(GetDefaultReceiver, 1, 1) \
\ \
F(GetPrototype, 1, 1) \ F(GetPrototype, 1, 1) \
F(SetPrototype, 2, 1) \
F(IsInPrototypeChain, 2, 1) \ F(IsInPrototypeChain, 2, 1) \
\ \
F(GetOwnProperty, 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); %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
%SetNativeFlag(f); %SetNativeFlag(f);
} }
prototype.__proto__ = null; %SetPrototype(prototype, null);
%ToFastProperties(prototype); %ToFastProperties(prototype);
} }
@ -1074,8 +1074,7 @@ function ObjectCreate(proto, properties) {
if (!IS_SPEC_OBJECT(proto) && proto !== null) { if (!IS_SPEC_OBJECT(proto) && proto !== null) {
throw MakeTypeError("proto_object_or_null", [proto]); throw MakeTypeError("proto_object_or_null", [proto]);
} }
var obj = new $Object(); var obj = { __proto__: proto };
obj.__proto__ = proto;
if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties); if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
return obj; return obj;
} }

View File

@ -1626,8 +1626,6 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
} }
break; break;
} }
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
__ push(Operand(rsp, 0)); // Duplicate receiver. __ push(Operand(rsp, 0)); // Duplicate receiver.
VisitForStackValue(key); VisitForStackValue(key);
VisitForStackValue(value); VisitForStackValue(value);
@ -1638,6 +1636,15 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
__ Drop(3); __ Drop(3);
} }
break; 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: case ObjectLiteral::Property::GETTER:
accessor_table.lookup(key)->second->getter = value; accessor_table.lookup(key)->second->getter = value;
break; break;