Revision: 5257
Author: [email protected]
Date: Thu Aug 12 23:55:44 2010
Log: Allow allocation in FailedAccessCheckCallback to allow embedders to
for instance throw exceptions in case of failed access checks.
Review URL: http://codereview.chromium.org/3165016
http://code.google.com/p/v8/source/detail?r=5257
Modified:
/branches/bleeding_edge/src/handles.cc
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/top.cc
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/src/handles.cc Wed Aug 11 06:48:58 2010
+++ /branches/bleeding_edge/src/handles.cc Thu Aug 12 23:55:44 2010
@@ -637,8 +637,8 @@
// Check access rights if required.
if (current->IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(*current, Heap::undefined_value(),
- v8::ACCESS_KEYS)) {
+ !Top::MayNamedAccess(*current, Heap::undefined_value(),
+ v8::ACCESS_KEYS)) {
Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
break;
}
=======================================
--- /branches/bleeding_edge/src/objects.cc Thu Aug 12 07:51:59 2010
+++ /branches/bleeding_edge/src/objects.cc Thu Aug 12 23:55:44 2010
@@ -1806,8 +1806,10 @@
}
}
+ HandleScope scope;
+ Handle<Object> value_handle(value);
Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
- return value;
+ return *value_handle;
}
@@ -6090,8 +6092,10 @@
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
!Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) {
+ HandleScope scope;
+ Handle<Object> value_handle(value);
Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
- return value;
+ return *value_handle;
}
if (IsJSGlobalProxy()) {
=======================================
--- /branches/bleeding_edge/src/top.cc Wed Aug 11 03:52:34 2010
+++ /branches/bleeding_edge/src/top.cc Thu Aug 12 23:55:44 2010
@@ -520,7 +520,6 @@
void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback
callback) {
- ASSERT(thread_local_.failed_access_check_callback_ == NULL);
thread_local_.failed_access_check_callback_ = callback;
}
@@ -530,8 +529,6 @@
ASSERT(receiver->IsAccessCheckNeeded());
ASSERT(Top::context());
- // The callers of this method are not expecting a GC.
- AssertNoAllocation no_gc;
// Get the data object from access check info.
JSFunction* constructor =
JSFunction::cast(receiver->map()->constructor());
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Tue Aug 10 03:05:18 2010
+++ /branches/bleeding_edge/test/cctest/test-api.cc Thu Aug 12 23:55:44 2010
@@ -81,12 +81,23 @@
static void ExpectTrue(const char* code) {
ExpectBoolean(code, true);
}
+
+
+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;
@@ -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);
+}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev