Commit d40abe33 authored by ager@chromium.org's avatar ager@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5257 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 9ef16704
...@@ -637,8 +637,8 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, ...@@ -637,8 +637,8 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
// Check access rights if required. // Check access rights if required.
if (current->IsAccessCheckNeeded() && if (current->IsAccessCheckNeeded() &&
!Top::MayNamedAccess(*current, Heap::undefined_value(), !Top::MayNamedAccess(*current, Heap::undefined_value(),
v8::ACCESS_KEYS)) { v8::ACCESS_KEYS)) {
Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS); Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
break; break;
} }
......
...@@ -1806,8 +1806,10 @@ Object* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result, ...@@ -1806,8 +1806,10 @@ Object* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
} }
} }
HandleScope scope;
Handle<Object> value_handle(value);
Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
return value; return *value_handle;
} }
...@@ -6090,8 +6092,10 @@ Object* JSObject::SetElement(uint32_t index, Object* value) { ...@@ -6090,8 +6092,10 @@ Object* JSObject::SetElement(uint32_t index, Object* value) {
// Check access rights if needed. // Check access rights if needed.
if (IsAccessCheckNeeded() && if (IsAccessCheckNeeded() &&
!Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) { !Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) {
HandleScope scope;
Handle<Object> value_handle(value);
Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
return value; return *value_handle;
} }
if (IsJSGlobalProxy()) { if (IsJSGlobalProxy()) {
......
...@@ -520,7 +520,6 @@ void Top::PrintStack(StringStream* accumulator) { ...@@ -520,7 +520,6 @@ void Top::PrintStack(StringStream* accumulator) {
void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) { void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) {
ASSERT(thread_local_.failed_access_check_callback_ == NULL);
thread_local_.failed_access_check_callback_ = callback; thread_local_.failed_access_check_callback_ = callback;
} }
...@@ -530,8 +529,6 @@ void Top::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) { ...@@ -530,8 +529,6 @@ void Top::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
ASSERT(receiver->IsAccessCheckNeeded()); ASSERT(receiver->IsAccessCheckNeeded());
ASSERT(Top::context()); ASSERT(Top::context());
// The callers of this method are not expecting a GC.
AssertNoAllocation no_gc;
// Get the data object from access check info. // Get the data object from access check info.
JSFunction* constructor = JSFunction::cast(receiver->map()->constructor()); JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
......
...@@ -83,12 +83,23 @@ static void ExpectTrue(const char* code) { ...@@ -83,12 +83,23 @@ static void ExpectTrue(const char* code) {
} }
static void ExpectFalse(const char* code) {
ExpectBoolean(code, false);
}
static void ExpectObject(const char* code, Local<Value> expected) { static void ExpectObject(const char* code, Local<Value> expected) {
Local<Value> result = CompileRun(code); Local<Value> result = CompileRun(code);
CHECK(result->Equals(expected)); CHECK(result->Equals(expected));
} }
static void ExpectUndefined(const char* code) {
Local<Value> result = CompileRun(code);
CHECK(result->IsUndefined());
}
static int signature_callback_count; static int signature_callback_count;
static v8::Handle<Value> IncrementingSignatureCallback( static v8::Handle<Value> IncrementingSignatureCallback(
const v8::Arguments& args) { const v8::Arguments& args) {
...@@ -11189,3 +11200,89 @@ THREADED_TEST(TwoByteStringInAsciiCons) { ...@@ -11189,3 +11200,89 @@ THREADED_TEST(TwoByteStringInAsciiCons) {
reresult = CompileRun("str2.charCodeAt(2);"); reresult = CompileRun("str2.charCodeAt(2);");
CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value()); 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment