Implement poison pill for non-strict mode function.caller
authormmaly@chromium.org <mmaly@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 23 Mar 2011 03:45:48 +0000 (03:45 +0000)
committermmaly@chromium.org <mmaly@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 23 Mar 2011 03:45:48 +0000 (03:45 +0000)
when caller is strict mode function.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7313 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/accessors.cc
src/messages.js
test/mjsunit/strict-mode.js

index 7326aed..af344d1 100644 (file)
@@ -827,6 +827,19 @@ const AccessorDescriptor Accessors::FunctionArguments = {
 //
 
 
+static MaybeObject* CheckNonStrictCallerOrThrow(
+    Isolate* isolate,
+    JSFunction* caller) {
+  DisableAssertNoAllocation enable_allocation;
+  if (caller->shared()->strict_mode()) {
+    return isolate->Throw(
+        *isolate->factory()->NewTypeError("strict_caller",
+                                          HandleVector<Object>(NULL, 0)));
+  }
+  return caller;
+}
+
+
 MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
   Isolate* isolate = Isolate::Current();
   HandleScope scope(isolate);
@@ -847,14 +860,14 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
         // frames, e.g. frames for scripts not functions.
         if (i > 0) {
           ASSERT(!functions[i - 1]->shared()->is_toplevel());
-          return functions[i - 1];
+          return CheckNonStrictCallerOrThrow(isolate, functions[i - 1]);
         } else {
           for (it.Advance(); !it.done(); it.Advance()) {
             frame = it.frame();
             functions.Rewind(0);
             frame->GetFunctions(&functions);
             if (!functions.last()->shared()->is_toplevel()) {
-              return functions.last();
+              return CheckNonStrictCallerOrThrow(isolate, functions.last());
             }
             ASSERT(functions.length() == 1);
           }
index 2ba12fd..3eb056f 100644 (file)
@@ -234,6 +234,7 @@ function FormatMessage(message) {
       strict_arguments_caller:      ["Cannot access property 'caller' of strict mode arguments"],
       strict_function_caller:       ["Cannot access property 'caller' of a strict mode function"],
       strict_function_arguments:    ["Cannot access property 'arguments' of a strict mode function"],
+      strict_caller:                ["Illegal access to a strict mode caller function."],
     };
   }
   var message_type = %MessageGetType(message);
index e8f6e1c..1f7666f 100644 (file)
@@ -1081,3 +1081,54 @@ function CheckPillDescriptor(func, name) {
   CheckPillDescriptor(args, "caller");
   CheckPillDescriptor(args, "callee");
 })();
+
+
+(function TestNonStrictFunctionCallerPillSimple() {
+  function return_my_caller() {
+    return return_my_caller.caller;
+  }
+
+  function strict() {
+    "use strict";
+    return_my_caller();
+  }
+  assertThrows(strict, TypeError);
+
+  function non_strict() {
+    return return_my_caller();
+  }
+  assertSame(non_strict(), non_strict);
+})();
+
+
+(function TestNonStrictFunctionCallerPill() {
+  function strict(n) {
+    "use strict";
+    non_strict(n);
+  }
+
+  function recurse(n, then) {
+    if (n > 0) {
+      recurse(n - 1);
+    } else {
+      return then();
+    }
+  }
+
+  function non_strict(n) {
+    recurse(n, function() { non_strict.caller; });
+  }
+
+  function test(n) {
+    try {
+      recurse(n, function() { strict(n); });
+    } catch(e) {
+      return e instanceof TypeError;
+    }
+    return false;
+  }
+
+  for (var i = 0; i < 10; i ++) {
+    assertEquals(test(i), true);
+  }
+})();