Index: test/cctest/test-api.cc |
=================================================================== |
--- test/cctest/test-api.cc (revision 5256) |
+++ test/cctest/test-api.cc (working copy) |
@@ -83,12 +83,23 @@ |
} |
+static void ExpectFalse(const char* code) { |
+ ExpectBoolean(code, false); |
+} |
+ |
+ |
static void ExpectObject(const char* code, Local<Value> expected) { |
Local<Value> result = CompileRun(code); |
CHECK(result->Equals(expected)); |
} |
+static void ExpectUndefined(const char* code) { |
+ Local<Value> result = CompileRun(code); |
+ CHECK(result->IsUndefined()); |
+} |
+ |
+ |
static int signature_callback_count; |
static v8::Handle<Value> IncrementingSignatureCallback( |
const v8::Arguments& args) { |
@@ -11189,3 +11200,89 @@ |
reresult = CompileRun("str2.charCodeAt(2);"); |
CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value()); |
} |
+ |
+ |
+// Failed access check callback that performs a GC on each invocation. |
+void FailedAccessCheckCallbackGC(Local<v8::Object> target, |
+ v8::AccessType type, |
+ Local<v8::Value> data) { |
+ i::Heap::CollectAllGarbage(true); |
+} |
+ |
+ |
+TEST(GCInFailedAccessCheckCallback) { |
+ // Install a failed access check callback that performs a GC on each |
+ // invocation. Then force the callback to be called from va |
+ |
+ v8::V8::Initialize(); |
+ v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC); |
+ |
+ v8::HandleScope scope; |
+ |
+ // Create an ObjectTemplate for global objects and install access |
+ // check callbacks that will block access. |
+ v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); |
+ global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, |
+ IndexedGetAccessBlocker, |
+ v8::Handle<v8::Value>(), |
+ false); |
+ |
+ // Create a context and set an x property on it's global object. |
+ LocalContext context0(NULL, global_template); |
+ context0->Global()->Set(v8_str("x"), v8_num(42)); |
+ v8::Handle<v8::Object> global0 = context0->Global(); |
+ |
+ // Create a context with a different security token so that the |
+ // failed access check callback will be called on each access. |
+ LocalContext context1(NULL, global_template); |
+ context1->Global()->Set(v8_str("other"), global0); |
+ |
+ // Get property with failed access check. |
+ ExpectUndefined("other.x"); |
+ |
+ // Get element with failed access check. |
+ ExpectUndefined("other[0]"); |
+ |
+ // Set property with failed access check. |
+ v8::Handle<v8::Value> result = CompileRun("other.x = new Object()"); |
+ CHECK(result->IsObject()); |
+ |
+ // Set element with failed access check. |
+ result = CompileRun("other[0] = new Object()"); |
+ CHECK(result->IsObject()); |
+ |
+ // Get property attribute with failed access check. |
+ ExpectFalse("\'x\' in other"); |
+ |
+ // Get property attribute for element with failed access check. |
+ ExpectFalse("0 in other"); |
+ |
+ // Delete property. |
+ ExpectFalse("delete other.x"); |
+ |
+ // Delete element. |
+ CHECK_EQ(false, global0->Delete(0)); |
+ |
+ // DefineAccessor. |
+ CHECK_EQ(false, |
+ global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x"))); |
+ |
+ // Define JavaScript accessor. |
+ ExpectUndefined("Object.prototype.__defineGetter__.call(" |
+ " other, \'x\', function() { return 42; })"); |
+ |
+ // LookupAccessor. |
+ ExpectUndefined("Object.prototype.__lookupGetter__.call(" |
+ " other, \'x\')"); |
+ |
+ // HasLocalElement. |
+ ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')"); |
+ |
+ CHECK_EQ(false, global0->HasRealIndexedProperty(0)); |
+ CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x"))); |
+ CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x"))); |
+ |
+ // Reset the failed access check callback so it does not influence |
+ // the other tests. |
+ v8::V8::SetFailedAccessCheckCallbackFunction(NULL); |
+} |