blob: 34b64c400a8550ae64279ccd3f2657e5802db688 [file] [log] [blame]
Ben Murdoch61f157c2016-09-16 13:49:30 +01001// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <stdlib.h>
6
7#include "test/cctest/cctest.h"
8
9namespace {
10
11int32_t g_cross_context_int = 0;
12
13void NamedGetter(v8::Local<v8::Name> property,
14 const v8::PropertyCallbackInfo<v8::Value>& info) {
15 v8::Isolate* isolate = info.GetIsolate();
16 v8::Local<v8::Context> context = isolate->GetCurrentContext();
17 if (property->Equals(context, v8_str("cross_context_int")).FromJust())
18 info.GetReturnValue().Set(g_cross_context_int);
19}
20
21void NamedSetter(v8::Local<v8::Name> property, v8::Local<v8::Value> value,
22 const v8::PropertyCallbackInfo<v8::Value>& info) {
23 v8::Isolate* isolate = info.GetIsolate();
24 v8::Local<v8::Context> context = isolate->GetCurrentContext();
25 if (!property->Equals(context, v8_str("cross_context_int")).FromJust())
26 return;
27 if (value->IsInt32()) {
28 g_cross_context_int = value->ToInt32(context).ToLocalChecked()->Value();
29 }
30 info.GetReturnValue().Set(value);
31}
32
33void NamedQuery(v8::Local<v8::Name> property,
34 const v8::PropertyCallbackInfo<v8::Integer>& info) {
35 v8::Isolate* isolate = info.GetIsolate();
36 v8::Local<v8::Context> context = isolate->GetCurrentContext();
37 if (!property->Equals(context, v8_str("cross_context_int")).FromJust())
38 return;
39 info.GetReturnValue().Set(v8::DontDelete);
40}
41
42void NamedDeleter(v8::Local<v8::Name> property,
43 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
44 v8::Isolate* isolate = info.GetIsolate();
45 v8::Local<v8::Context> context = isolate->GetCurrentContext();
46 if (!property->Equals(context, v8_str("cross_context_int")).FromJust())
47 return;
48 info.GetReturnValue().Set(false);
49}
50
51void NamedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
52 v8::Isolate* isolate = info.GetIsolate();
53 v8::Local<v8::Context> context = isolate->GetCurrentContext();
54 v8::Local<v8::Array> names = v8::Array::New(isolate, 1);
55 names->Set(context, 0, v8_str("cross_context_int")).FromJust();
56 info.GetReturnValue().Set(names);
57}
58
59void IndexedGetter(uint32_t index,
60 const v8::PropertyCallbackInfo<v8::Value>& info) {
61 if (index == 7) info.GetReturnValue().Set(g_cross_context_int);
62}
63
64void IndexedSetter(uint32_t index, v8::Local<v8::Value> value,
65 const v8::PropertyCallbackInfo<v8::Value>& info) {
66 v8::Isolate* isolate = info.GetIsolate();
67 v8::Local<v8::Context> context = isolate->GetCurrentContext();
68 if (index != 7) return;
69 if (value->IsInt32()) {
70 g_cross_context_int = value->ToInt32(context).ToLocalChecked()->Value();
71 }
72 info.GetReturnValue().Set(value);
73}
74
75void IndexedQuery(uint32_t index,
76 const v8::PropertyCallbackInfo<v8::Integer>& info) {
77 if (index == 7) info.GetReturnValue().Set(v8::DontDelete);
78}
79
80void IndexedDeleter(uint32_t index,
81 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
82 if (index == 7) info.GetReturnValue().Set(false);
83}
84
85void IndexedEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
86 v8::Isolate* isolate = info.GetIsolate();
87 v8::Local<v8::Context> context = isolate->GetCurrentContext();
88 v8::Local<v8::Array> names = v8::Array::New(isolate, 1);
89 names->Set(context, 0, v8_str("7")).FromJust();
90 info.GetReturnValue().Set(names);
91}
92
93bool AccessCheck(v8::Local<v8::Context> accessing_context,
94 v8::Local<v8::Object> accessed_object,
95 v8::Local<v8::Value> data) {
96 return false;
97}
98
99void GetCrossContextInt(v8::Local<v8::String> property,
100 const v8::PropertyCallbackInfo<v8::Value>& info) {
101 info.GetReturnValue().Set(g_cross_context_int);
102}
103
104void SetCrossContextInt(v8::Local<v8::String> property,
105 v8::Local<v8::Value> value,
106 const v8::PropertyCallbackInfo<void>& info) {
107 v8::Isolate* isolate = info.GetIsolate();
108 v8::Local<v8::Context> context = isolate->GetCurrentContext();
109 if (value->IsInt32()) {
110 g_cross_context_int = value->ToInt32(context).ToLocalChecked()->Value();
111 }
112}
113
114void Return42(v8::Local<v8::String> property,
115 const v8::PropertyCallbackInfo<v8::Value>& info) {
116 info.GetReturnValue().Set(42);
117}
118
119} // namespace
120
121TEST(AccessCheckWithInterceptor) {
122 v8::Isolate* isolate = CcTest::isolate();
123 v8::HandleScope scope(isolate);
124 v8::Local<v8::ObjectTemplate> global_template =
125 v8::ObjectTemplate::New(isolate);
126 global_template->SetAccessCheckCallbackAndHandler(
127 AccessCheck,
128 v8::NamedPropertyHandlerConfiguration(
129 NamedGetter, NamedSetter, NamedQuery, NamedDeleter, NamedEnumerator),
130 v8::IndexedPropertyHandlerConfiguration(IndexedGetter, IndexedSetter,
131 IndexedQuery, IndexedDeleter,
132 IndexedEnumerator));
133 global_template->SetNativeDataProperty(
134 v8_str("cross_context_int"), GetCrossContextInt, SetCrossContextInt);
135 global_template->SetNativeDataProperty(
136 v8_str("all_can_read"), Return42, nullptr, v8::Local<v8::Value>(),
137 v8::None, v8::Local<v8::AccessorSignature>(), v8::ALL_CAN_READ);
138
139 v8::Local<v8::Context> context0 =
140 v8::Context::New(isolate, nullptr, global_template);
141 context0->Enter();
142
143 // Running script in this context should work.
144 CompileRunChecked(isolate, "this.foo = 42; this[23] = true;");
145 ExpectInt32("this.all_can_read", 42);
146 CompileRunChecked(isolate, "this.cross_context_int = 23");
147 CHECK_EQ(g_cross_context_int, 23);
148 ExpectInt32("this.cross_context_int", 23);
149
150 // Create another context.
151 {
152 v8::HandleScope other_scope(isolate);
153 v8::Local<v8::Context> context1 =
154 v8::Context::New(isolate, nullptr, global_template);
155 context1->Global()
156 ->Set(context1, v8_str("other"), context0->Global())
157 .FromJust();
158 v8::Context::Scope context_scope(context1);
159
160 {
161 v8::TryCatch try_catch(isolate);
162 CHECK(CompileRun(context1, "this.other.foo").IsEmpty());
163 }
164 {
165 v8::TryCatch try_catch(isolate);
166 CHECK(CompileRun(context1, "this.other[23]").IsEmpty());
167 }
168
169 // AllCanRead properties are also inaccessible.
170 {
171 v8::TryCatch try_catch(isolate);
172 CHECK(CompileRun(context1, "this.other.all_can_read").IsEmpty());
173 }
174
175 // Intercepted properties are accessible, however.
176 ExpectInt32("this.other.cross_context_int", 23);
177 CompileRunChecked(isolate, "this.other.cross_context_int = 42");
178 ExpectInt32("this.other[7]", 42);
179 ExpectString("JSON.stringify(Object.getOwnPropertyNames(this.other))",
180 "[\"7\",\"cross_context_int\"]");
181 }
182}