From 0ca02ee48d764bec60fb834d0e42e1452942f818 Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Mon, 4 Mar 2013 16:05:12 +0000 Subject: [PATCH] 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 --- src/apinatives.js | 2 +- src/arm/full-codegen-arm.cc | 14 ++++++++++++-- src/array.js | 6 +++--- src/d8.js | 2 +- src/ia32/full-codegen-ia32.cc | 11 +++++++++-- src/math.js | 2 +- src/messages.js | 2 +- src/mips/full-codegen-mips.cc | 13 +++++++++++-- src/objects.h | 2 +- src/proxy.js | 3 +-- src/runtime.cc | 9 +++++++++ src/runtime.h | 1 + src/v8natives.js | 5 ++--- src/x64/full-codegen-x64.cc | 11 +++++++++-- 14 files changed, 62 insertions(+), 21 deletions(-) diff --git a/src/apinatives.js b/src/apinatives.js index 79b41dd..ad1d869 100644 --- a/src/apinatives.js +++ b/src/apinatives.js @@ -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) { diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 04634d6..d3c1957 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -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; diff --git a/src/array.js b/src/array.js index 9b0bfe1..1ec6433 100644 --- a/src/array.js +++ b/src/array.js @@ -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]; diff --git a/src/d8.js b/src/d8.js index 3cb1819..6a4ecb7 100644 --- a/src/d8.js +++ b/src/d8.js @@ -71,7 +71,7 @@ function GetCompletions(global, last, full) { result.push(name); } } - current = ToInspectableObject(current.__proto__); + current = ToInspectableObject(Object.getPrototypeOf(current)); } return result; } diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 1428dfe..166cb6f 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -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; diff --git a/src/math.js b/src/math.js index 4686328..0e02541 100644 --- a/src/math.js +++ b/src/math.js @@ -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 diff --git a/src/messages.js b/src/messages.js index 14ba73f..7353444 100644 --- a/src/messages.js +++ b/src/messages.js @@ -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]; diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 8046216..54eeb8d 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -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; diff --git a/src/objects.h b/src/objects.h index 1ecc3ef..5020b73 100644 --- a/src/objects.h +++ b/src/objects.h @@ -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)); } diff --git a/src/proxy.js b/src/proxy.js index 285d33c..7997923 100644 --- a/src/proxy.js +++ b/src/proxy.js @@ -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 } diff --git a/src/runtime.cc b/src/runtime.cc index bd18302..73ff7b8 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -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); diff --git a/src/runtime.h b/src/runtime.h index a0f4fe7..cd6805c 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -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) \ diff --git a/src/v8natives.js b/src/v8natives.js index 259856b..fbebbe7 100644 --- a/src/v8natives.js +++ b/src/v8natives.js @@ -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; } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index fa1d948..299fc45 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -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; -- 2.7.4