Make sure builtin functions don't rely on __proto__.
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 4 Mar 2013 16:05:12 +0000 (16:05 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 4 Mar 2013 16:05:12 +0000 (16:05 +0000)
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

14 files changed:
src/apinatives.js
src/arm/full-codegen-arm.cc
src/array.js
src/d8.js
src/ia32/full-codegen-ia32.cc
src/math.js
src/messages.js
src/mips/full-codegen-mips.cc
src/objects.h
src/proxy.js
src/runtime.cc
src/runtime.h
src/v8natives.js
src/x64/full-codegen-x64.cc

index 79b41dd..ad1d869 100644 (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) {
index 04634d6..d3c1957 100644 (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;
index 9b0bfe1..1ec6433 100644 (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];
index 3cb1819..6a4ecb7 100644 (file)
--- 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;
 }
index 1428dfe..166cb6f 100644 (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;
index 4686328..0e02541 100644 (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
index 14ba73f..7353444 100644 (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];
index 8046216..54eeb8d 100644 (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;
index 1ecc3ef..5020b73 100644 (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));
   }
index 285d33c..7997923 100644 (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
   }
index bd18302..73ff7b8 100644 (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);
index a0f4fe7..cd6805c 100644 (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) \
index 259856b..fbebbe7 100644 (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;
 }
index fa1d948..299fc45 100644 (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;