Line data Source code
1 : // Copyright 2012 the V8 project authors. All rights reserved.
2 : // Redistribution and use in source and binary forms, with or without
3 : // modification, are permitted provided that the following conditions are
4 : // met:
5 : //
6 : // * Redistributions of source code must retain the above copyright
7 : // notice, this list of conditions and the following disclaimer.
8 : // * Redistributions in binary form must reproduce the above
9 : // copyright notice, this list of conditions and the following
10 : // disclaimer in the documentation and/or other materials provided
11 : // with the distribution.
12 : // * Neither the name of Google Inc. nor the names of its
13 : // contributors may be used to endorse or promote products derived
14 : // from this software without specific prior written permission.
15 : //
16 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 :
28 : #include <stdlib.h>
29 :
30 : #include "src/v8.h"
31 :
32 : #include "src/api-inl.h"
33 : #include "src/frames-inl.h"
34 : #include "src/string-stream.h"
35 : #include "test/cctest/cctest.h"
36 :
37 : using ::v8::ObjectTemplate;
38 : using ::v8::Value;
39 : using ::v8::Context;
40 : using ::v8::Local;
41 : using ::v8::Name;
42 : using ::v8::String;
43 : using ::v8::Script;
44 : using ::v8::Function;
45 : using ::v8::Extension;
46 :
47 24 : static void handle_property(Local<String> name,
48 : const v8::PropertyCallbackInfo<v8::Value>& info) {
49 24 : ApiTestFuzzer::Fuzz();
50 24 : info.GetReturnValue().Set(v8_num(900));
51 24 : }
52 :
53 24 : static void handle_property_2(Local<String> name,
54 : const v8::PropertyCallbackInfo<v8::Value>& info) {
55 24 : ApiTestFuzzer::Fuzz();
56 24 : info.GetReturnValue().Set(v8_num(902));
57 24 : }
58 :
59 :
60 309 : static void handle_property(const v8::FunctionCallbackInfo<v8::Value>& info) {
61 103 : ApiTestFuzzer::Fuzz();
62 103 : CHECK_EQ(0, info.Length());
63 103 : info.GetReturnValue().Set(v8_num(907));
64 103 : }
65 :
66 :
67 25881 : THREADED_TEST(PropertyHandler) {
68 6 : LocalContext env;
69 6 : v8::Isolate* isolate = env->GetIsolate();
70 12 : v8::HandleScope scope(isolate);
71 6 : Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
72 12 : fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
73 : Local<v8::FunctionTemplate> getter_templ =
74 6 : v8::FunctionTemplate::New(isolate, handle_property);
75 6 : getter_templ->SetLength(0);
76 : fun_templ->
77 18 : InstanceTemplate()->SetAccessorProperty(v8_str("bar"), getter_templ);
78 12 : fun_templ->InstanceTemplate()->
79 18 : SetNativeDataProperty(v8_str("instance_foo"), handle_property);
80 6 : fun_templ->SetNativeDataProperty(v8_str("object_foo"), handle_property_2);
81 6 : Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked();
82 30 : CHECK(env->Global()->Set(env.local(), v8_str("Fun"), fun).FromJust());
83 : Local<Script> getter;
84 : Local<Script> setter;
85 : // check function instance accessors
86 : getter = v8_compile("var obj = new Fun(); obj.instance_foo;");
87 30 : for (int i = 0; i < 4; i++) {
88 72 : CHECK_EQ(900, getter->Run(env.local())
89 : .ToLocalChecked()
90 : ->Int32Value(env.local())
91 : .FromJust());
92 : }
93 : setter = v8_compile("obj.instance_foo = 901;");
94 30 : for (int i = 0; i < 4; i++) {
95 72 : CHECK_EQ(901, setter->Run(env.local())
96 : .ToLocalChecked()
97 : ->Int32Value(env.local())
98 : .FromJust());
99 : }
100 : getter = v8_compile("obj.bar;");
101 30 : for (int i = 0; i < 4; i++) {
102 72 : CHECK_EQ(907, getter->Run(env.local())
103 : .ToLocalChecked()
104 : ->Int32Value(env.local())
105 : .FromJust());
106 : }
107 : setter = v8_compile("obj.bar = 908;");
108 30 : for (int i = 0; i < 4; i++) {
109 72 : CHECK_EQ(908, setter->Run(env.local())
110 : .ToLocalChecked()
111 : ->Int32Value(env.local())
112 : .FromJust());
113 : }
114 : // check function static accessors
115 : getter = v8_compile("Fun.object_foo;");
116 30 : for (int i = 0; i < 4; i++) {
117 72 : CHECK_EQ(902, getter->Run(env.local())
118 : .ToLocalChecked()
119 : ->Int32Value(env.local())
120 : .FromJust());
121 : }
122 : setter = v8_compile("Fun.object_foo = 903;");
123 30 : for (int i = 0; i < 4; i++) {
124 72 : CHECK_EQ(903, setter->Run(env.local())
125 : .ToLocalChecked()
126 : ->Int32Value(env.local())
127 : .FromJust());
128 : }
129 :
130 : // And now with null prototype.
131 6 : CompileRun(env.local(), "obj.__proto__ = null;");
132 : getter = v8_compile("obj.bar;");
133 30 : for (int i = 0; i < 4; i++) {
134 72 : CHECK_EQ(907, getter->Run(env.local())
135 : .ToLocalChecked()
136 : ->Int32Value(env.local())
137 : .FromJust());
138 : }
139 : setter = v8_compile("obj.bar = 908;");
140 30 : for (int i = 0; i < 4; i++) {
141 72 : CHECK_EQ(908, setter->Run(env.local())
142 : .ToLocalChecked()
143 : ->Int32Value(env.local())
144 : .FromJust());
145 6 : }
146 6 : }
147 :
148 :
149 12 : static void GetIntValue(Local<String> property,
150 : const v8::PropertyCallbackInfo<v8::Value>& info) {
151 12 : ApiTestFuzzer::Fuzz();
152 : int* value =
153 12 : static_cast<int*>(v8::Local<v8::External>::Cast(info.Data())->Value());
154 12 : info.GetReturnValue().Set(v8_num(*value));
155 12 : }
156 :
157 :
158 12 : static void SetIntValue(Local<String> property,
159 : Local<Value> value,
160 : const v8::PropertyCallbackInfo<void>& info) {
161 : int* field =
162 12 : static_cast<int*>(v8::Local<v8::External>::Cast(info.Data())->Value());
163 36 : *field = value->Int32Value(info.GetIsolate()->GetCurrentContext()).FromJust();
164 12 : }
165 :
166 : int foo, bar, baz;
167 :
168 25881 : THREADED_TEST(GlobalVariableAccess) {
169 6 : foo = 0;
170 6 : bar = -4;
171 6 : baz = 10;
172 6 : v8::Isolate* isolate = CcTest::isolate();
173 6 : v8::HandleScope scope(isolate);
174 6 : v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
175 : templ->InstanceTemplate()->SetAccessor(
176 : v8_str("foo"), GetIntValue, SetIntValue,
177 18 : v8::External::New(isolate, &foo));
178 : templ->InstanceTemplate()->SetAccessor(
179 : v8_str("bar"), GetIntValue, SetIntValue,
180 18 : v8::External::New(isolate, &bar));
181 : templ->InstanceTemplate()->SetAccessor(
182 : v8_str("baz"), GetIntValue, SetIntValue,
183 12 : v8::External::New(isolate, &baz));
184 12 : LocalContext env(nullptr, templ->InstanceTemplate());
185 12 : v8_compile("foo = (++bar) + baz")->Run(env.local()).ToLocalChecked();
186 6 : CHECK_EQ(-3, bar);
187 12 : CHECK_EQ(7, foo);
188 6 : }
189 :
190 :
191 : static int x_register[2] = {0, 0};
192 : static v8::Local<v8::Object> x_receiver;
193 : static v8::Local<v8::Object> x_holder;
194 :
195 : template<class Info>
196 600 : static void XGetter(const Info& info, int offset) {
197 240 : ApiTestFuzzer::Fuzz();
198 240 : v8::Isolate* isolate = CcTest::isolate();
199 240 : CHECK_EQ(isolate, info.GetIsolate());
200 720 : CHECK(
201 : x_receiver->Equals(isolate->GetCurrentContext(), info.This()).FromJust());
202 240 : info.GetReturnValue().Set(v8_num(x_register[offset]));
203 240 : }
204 :
205 :
206 120 : static void XGetter(Local<String> name,
207 : const v8::PropertyCallbackInfo<v8::Value>& info) {
208 360 : CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
209 : .FromJust());
210 120 : XGetter(info, 0);
211 120 : }
212 :
213 :
214 120 : static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
215 360 : CHECK(
216 : x_receiver->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
217 : .FromJust());
218 120 : XGetter(info, 1);
219 120 : }
220 :
221 :
222 : template<class Info>
223 840 : static void XSetter(Local<Value> value, const Info& info, int offset) {
224 240 : v8::Isolate* isolate = CcTest::isolate();
225 240 : CHECK_EQ(isolate, info.GetIsolate());
226 720 : CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.This())
227 : .FromJust());
228 720 : CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder())
229 : .FromJust());
230 720 : x_register[offset] =
231 : value->Int32Value(info.GetIsolate()->GetCurrentContext()).FromJust();
232 240 : info.GetReturnValue().Set(v8_num(-1));
233 240 : }
234 :
235 :
236 120 : static void XSetter(Local<String> name,
237 : Local<Value> value,
238 : const v8::PropertyCallbackInfo<void>& info) {
239 120 : XSetter(value, info, 0);
240 120 : }
241 :
242 :
243 120 : static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
244 120 : CHECK_EQ(1, info.Length());
245 120 : XSetter(info[0], info, 1);
246 120 : }
247 :
248 :
249 25881 : THREADED_TEST(AccessorIC) {
250 6 : LocalContext context;
251 6 : v8::Isolate* isolate = context->GetIsolate();
252 12 : v8::HandleScope scope(isolate);
253 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
254 6 : obj->SetAccessor(v8_str("x0"), XGetter, XSetter);
255 : obj->SetAccessorProperty(v8_str("x1"),
256 : v8::FunctionTemplate::New(isolate, XGetter),
257 18 : v8::FunctionTemplate::New(isolate, XSetter));
258 12 : x_holder = obj->NewInstance(context.local()).ToLocalChecked();
259 30 : CHECK(context->Global()
260 : ->Set(context.local(), v8_str("holder"), x_holder)
261 : .FromJust());
262 6 : x_receiver = v8::Object::New(isolate);
263 30 : CHECK(context->Global()
264 : ->Set(context.local(), v8_str("obj"), x_receiver)
265 : .FromJust());
266 : v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(
267 : CompileRun("obj.__proto__ = holder;"
268 : "var result = [];"
269 : "var key_0 = 'x0';"
270 : "var key_1 = 'x1';"
271 : "for (var j = 0; j < 10; j++) {"
272 : " var i = 4*j;"
273 : " result.push(holder.x0 = i);"
274 : " result.push(obj.x0);"
275 : " result.push(holder.x1 = i + 1);"
276 : " result.push(obj.x1);"
277 : " result.push(holder[key_0] = i + 2);"
278 : " result.push(obj[key_0]);"
279 : " result.push(holder[key_1] = i + 3);"
280 : " result.push(obj[key_1]);"
281 : "}"
282 : "result"));
283 6 : CHECK_EQ(80u, array->Length());
284 480 : for (int i = 0; i < 80; i++) {
285 : v8::Local<Value> entry =
286 1440 : array->Get(context.local(), v8::Integer::New(isolate, i))
287 960 : .ToLocalChecked();
288 1440 : CHECK(v8::Integer::New(isolate, i / 2)
289 : ->Equals(context.local(), entry)
290 : .FromJust());
291 6 : }
292 6 : }
293 :
294 :
295 : template <int C>
296 12000 : static void HandleAllocatingGetter(
297 : Local<String> name,
298 : const v8::PropertyCallbackInfo<v8::Value>& info) {
299 12000 : ApiTestFuzzer::Fuzz();
300 6162000 : for (int i = 0; i < C; i++) {
301 : v8::String::NewFromUtf8(info.GetIsolate(), "foo",
302 : v8::NewStringType::kNormal)
303 6150000 : .ToLocalChecked();
304 : }
305 : info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "foo",
306 : v8::NewStringType::kNormal)
307 12000 : .ToLocalChecked());
308 12000 : }
309 :
310 :
311 25881 : THREADED_TEST(HandleScopePop) {
312 6 : LocalContext context;
313 6 : v8::Isolate* isolate = context->GetIsolate();
314 12 : v8::HandleScope scope(isolate);
315 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
316 6 : obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>);
317 6 : obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>);
318 : v8::Local<v8::Object> inst =
319 6 : obj->NewInstance(context.local()).ToLocalChecked();
320 30 : CHECK(
321 : context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
322 : int count_before =
323 6 : i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
324 : {
325 6 : v8::HandleScope scope(isolate);
326 : CompileRun(
327 : "for (var i = 0; i < 1000; i++) {"
328 : " obj.one;"
329 : " obj.many;"
330 6 : "}");
331 : }
332 : int count_after =
333 6 : i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate));
334 12 : CHECK_EQ(count_before, count_after);
335 6 : }
336 :
337 264 : static void CheckAccessorArgsCorrect(
338 : Local<String> name,
339 : const v8::PropertyCallbackInfo<v8::Value>& info) {
340 264 : CHECK(info.GetIsolate() == CcTest::isolate());
341 264 : CHECK(info.This() == info.Holder());
342 1056 : CHECK(info.Data()
343 : ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
344 : .FromJust());
345 264 : ApiTestFuzzer::Fuzz();
346 264 : CHECK(info.GetIsolate() == CcTest::isolate());
347 264 : CHECK(info.This() == info.Holder());
348 1056 : CHECK(info.Data()
349 : ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
350 : .FromJust());
351 264 : CcTest::CollectAllGarbage();
352 264 : CHECK(info.GetIsolate() == CcTest::isolate());
353 264 : CHECK(info.This() == info.Holder());
354 1056 : CHECK(info.Data()
355 : ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data"))
356 : .FromJust());
357 : info.GetReturnValue().Set(17);
358 264 : }
359 :
360 :
361 25881 : THREADED_TEST(DirectCall) {
362 6 : LocalContext context;
363 6 : v8::Isolate* isolate = context->GetIsolate();
364 12 : v8::HandleScope scope(isolate);
365 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
366 : obj->SetAccessor(v8_str("xxx"), CheckAccessorArgsCorrect, nullptr,
367 12 : v8_str("data"));
368 : v8::Local<v8::Object> inst =
369 6 : obj->NewInstance(context.local()).ToLocalChecked();
370 30 : CHECK(
371 : context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
372 : Local<Script> scr =
373 6 : v8::Script::Compile(context.local(), v8_str("obj.xxx")).ToLocalChecked();
374 60 : for (int i = 0; i < 10; i++) {
375 60 : Local<Value> result = scr->Run(context.local()).ToLocalChecked();
376 60 : CHECK(!result.IsEmpty());
377 120 : CHECK_EQ(17, result->Int32Value(context.local()).FromJust());
378 6 : }
379 6 : }
380 :
381 72 : static void EmptyGetter(Local<String> name,
382 : const v8::PropertyCallbackInfo<v8::Value>& info) {
383 72 : CheckAccessorArgsCorrect(name, info);
384 72 : ApiTestFuzzer::Fuzz();
385 72 : CheckAccessorArgsCorrect(name, info);
386 : info.GetReturnValue().Set(v8::Local<v8::Value>());
387 72 : }
388 :
389 :
390 25881 : THREADED_TEST(EmptyResult) {
391 6 : LocalContext context;
392 6 : v8::Isolate* isolate = context->GetIsolate();
393 12 : v8::HandleScope scope(isolate);
394 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
395 12 : obj->SetAccessor(v8_str("xxx"), EmptyGetter, nullptr, v8_str("data"));
396 : v8::Local<v8::Object> inst =
397 6 : obj->NewInstance(context.local()).ToLocalChecked();
398 30 : CHECK(
399 : context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust());
400 : Local<Script> scr =
401 6 : v8::Script::Compile(context.local(), v8_str("obj.xxx")).ToLocalChecked();
402 60 : for (int i = 0; i < 10; i++) {
403 60 : Local<Value> result = scr->Run(context.local()).ToLocalChecked();
404 60 : CHECK(result == v8::Undefined(isolate));
405 6 : }
406 6 : }
407 :
408 :
409 25881 : THREADED_TEST(NoReuseRegress) {
410 : // Check that the IC generated for the one test doesn't get reused
411 : // for the other.
412 6 : v8::Isolate* isolate = CcTest::isolate();
413 6 : v8::HandleScope scope(isolate);
414 : {
415 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
416 12 : obj->SetAccessor(v8_str("xxx"), EmptyGetter, nullptr, v8_str("data"));
417 6 : LocalContext context;
418 : v8::Local<v8::Object> inst =
419 6 : obj->NewInstance(context.local()).ToLocalChecked();
420 30 : CHECK(context->Global()
421 : ->Set(context.local(), v8_str("obj"), inst)
422 : .FromJust());
423 6 : Local<Script> scr = v8::Script::Compile(context.local(), v8_str("obj.xxx"))
424 6 : .ToLocalChecked();
425 12 : for (int i = 0; i < 2; i++) {
426 12 : Local<Value> result = scr->Run(context.local()).ToLocalChecked();
427 12 : CHECK(result == v8::Undefined(isolate));
428 6 : }
429 : }
430 : {
431 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
432 : obj->SetAccessor(v8_str("xxx"), CheckAccessorArgsCorrect, nullptr,
433 12 : v8_str("data"));
434 6 : LocalContext context;
435 : v8::Local<v8::Object> inst =
436 6 : obj->NewInstance(context.local()).ToLocalChecked();
437 30 : CHECK(context->Global()
438 : ->Set(context.local(), v8_str("obj"), inst)
439 : .FromJust());
440 6 : Local<Script> scr = v8::Script::Compile(context.local(), v8_str("obj.xxx"))
441 6 : .ToLocalChecked();
442 60 : for (int i = 0; i < 10; i++) {
443 60 : Local<Value> result = scr->Run(context.local()).ToLocalChecked();
444 60 : CHECK(!result.IsEmpty());
445 120 : CHECK_EQ(17, result->Int32Value(context.local()).FromJust());
446 6 : }
447 6 : }
448 6 : }
449 :
450 30 : static void ThrowingGetAccessor(
451 : Local<String> name,
452 : const v8::PropertyCallbackInfo<v8::Value>& info) {
453 30 : ApiTestFuzzer::Fuzz();
454 60 : info.GetIsolate()->ThrowException(v8_str("g"));
455 30 : }
456 :
457 :
458 30 : static void ThrowingSetAccessor(Local<String> name,
459 : Local<Value> value,
460 : const v8::PropertyCallbackInfo<void>& info) {
461 30 : info.GetIsolate()->ThrowException(value);
462 30 : }
463 :
464 :
465 25881 : THREADED_TEST(Regress1054726) {
466 6 : LocalContext env;
467 6 : v8::Isolate* isolate = env->GetIsolate();
468 12 : v8::HandleScope scope(isolate);
469 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
470 : obj->SetAccessor(v8_str("x"),
471 : ThrowingGetAccessor,
472 : ThrowingSetAccessor,
473 6 : Local<Value>());
474 :
475 36 : CHECK(env->Global()
476 : ->Set(env.local(), v8_str("obj"),
477 : obj->NewInstance(env.local()).ToLocalChecked())
478 : .FromJust());
479 :
480 : // Use the throwing property setter/getter in a loop to force
481 : // the accessor ICs to be initialized.
482 : v8::Local<Value> result;
483 : result = Script::Compile(env.local(),
484 : v8_str("var result = '';"
485 : "for (var i = 0; i < 5; i++) {"
486 : " try { obj.x; } catch (e) { result += e; }"
487 6 : "}; result"))
488 6 : .ToLocalChecked()
489 6 : ->Run(env.local())
490 12 : .ToLocalChecked();
491 18 : CHECK(v8_str("ggggg")->Equals(env.local(), result).FromJust());
492 :
493 : result =
494 : Script::Compile(env.local(),
495 : v8_str("var result = '';"
496 : "for (var i = 0; i < 5; i++) {"
497 : " try { obj.x = i; } catch (e) { result += e; }"
498 6 : "}; result"))
499 6 : .ToLocalChecked()
500 6 : ->Run(env.local())
501 12 : .ToLocalChecked();
502 24 : CHECK(v8_str("01234")->Equals(env.local(), result).FromJust());
503 6 : }
504 :
505 :
506 12288 : static void AllocGetter(Local<String> name,
507 : const v8::PropertyCallbackInfo<v8::Value>& info) {
508 12288 : ApiTestFuzzer::Fuzz();
509 12288 : info.GetReturnValue().Set(v8::Array::New(info.GetIsolate(), 1000));
510 12288 : }
511 :
512 :
513 25881 : THREADED_TEST(Gc) {
514 6 : LocalContext env;
515 6 : v8::Isolate* isolate = env->GetIsolate();
516 12 : v8::HandleScope scope(isolate);
517 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
518 6 : obj->SetAccessor(v8_str("xxx"), AllocGetter);
519 36 : CHECK(env->Global()
520 : ->Set(env.local(), v8_str("obj"),
521 : obj->NewInstance(env.local()).ToLocalChecked())
522 : .FromJust());
523 : Script::Compile(env.local(), v8_str("var last = [];"
524 : "for (var i = 0; i < 2048; i++) {"
525 : " var result = obj.xxx;"
526 : " result[0] = last;"
527 : " last = result;"
528 6 : "}"))
529 6 : .ToLocalChecked()
530 6 : ->Run(env.local())
531 12 : .ToLocalChecked();
532 6 : }
533 :
534 :
535 600 : static void StackCheck(Local<String> name,
536 : const v8::PropertyCallbackInfo<v8::Value>& info) {
537 600 : i::StackFrameIterator iter(reinterpret_cast<i::Isolate*>(info.GetIsolate()));
538 4100 : for (int i = 0; !iter.done(); i++) {
539 : i::StackFrame* frame = iter.frame();
540 3500 : CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT));
541 3500 : i::Code code = frame->LookupCode();
542 3500 : CHECK(code->IsCode());
543 3500 : CHECK(code->contains(frame->pc()));
544 3500 : iter.Advance();
545 : }
546 600 : }
547 :
548 :
549 25881 : THREADED_TEST(StackIteration) {
550 6 : LocalContext env;
551 6 : v8::Isolate* isolate = env->GetIsolate();
552 12 : v8::HandleScope scope(isolate);
553 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
554 : i::StringStream::ClearMentionedObjectCache(
555 6 : reinterpret_cast<i::Isolate*>(isolate));
556 6 : obj->SetAccessor(v8_str("xxx"), StackCheck);
557 36 : CHECK(env->Global()
558 : ->Set(env.local(), v8_str("obj"),
559 : obj->NewInstance(env.local()).ToLocalChecked())
560 : .FromJust());
561 : Script::Compile(env.local(), v8_str("function foo() {"
562 : " return obj.xxx;"
563 : "}"
564 : "for (var i = 0; i < 100; i++) {"
565 : " foo();"
566 6 : "}"))
567 6 : .ToLocalChecked()
568 6 : ->Run(env.local())
569 12 : .ToLocalChecked();
570 6 : }
571 :
572 :
573 24 : static void AllocateHandles(Local<String> name,
574 : const v8::PropertyCallbackInfo<v8::Value>& info) {
575 24576 : for (int i = 0; i < i::kHandleBlockSize + 1; i++) {
576 : v8::Local<v8::Value>::New(info.GetIsolate(), name);
577 : }
578 24 : info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 100));
579 24 : }
580 :
581 :
582 25881 : THREADED_TEST(HandleScopeSegment) {
583 : // Check that we can return values past popping of handle scope
584 : // segments.
585 6 : LocalContext env;
586 6 : v8::Isolate* isolate = env->GetIsolate();
587 12 : v8::HandleScope scope(isolate);
588 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
589 6 : obj->SetAccessor(v8_str("xxx"), AllocateHandles);
590 36 : CHECK(env->Global()
591 : ->Set(env.local(), v8_str("obj"),
592 : obj->NewInstance(env.local()).ToLocalChecked())
593 : .FromJust());
594 : v8::Local<v8::Value> result =
595 : Script::Compile(env.local(), v8_str("var result;"
596 : "for (var i = 0; i < 4; i++)"
597 : " result = obj.xxx;"
598 6 : "result;"))
599 6 : .ToLocalChecked()
600 6 : ->Run(env.local())
601 6 : .ToLocalChecked();
602 18 : CHECK_EQ(100, result->Int32Value(env.local()).FromJust());
603 6 : }
604 :
605 :
606 6 : void JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
607 6 : v8::Local<v8::Array> array = v8::Array::New(info.GetIsolate(), 1);
608 24 : CHECK(array->Set(info.GetIsolate()->GetCurrentContext(), 0, v8_str("regress"))
609 : .FromJust());
610 : info.GetReturnValue().Set(array);
611 6 : }
612 :
613 :
614 6 : void JSONStringifyGetter(Local<Name> name,
615 : const v8::PropertyCallbackInfo<v8::Value>& info) {
616 6 : info.GetReturnValue().Set(v8_str("crbug-161028"));
617 6 : }
618 :
619 :
620 25881 : THREADED_TEST(JSONStringifyNamedInterceptorObject) {
621 6 : LocalContext env;
622 6 : v8::Isolate* isolate = env->GetIsolate();
623 12 : v8::HandleScope scope(isolate);
624 :
625 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
626 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
627 6 : JSONStringifyGetter, nullptr, nullptr, nullptr, JSONStringifyEnumerator));
628 36 : CHECK(env->Global()
629 : ->Set(env.local(), v8_str("obj"),
630 : obj->NewInstance(env.local()).ToLocalChecked())
631 : .FromJust());
632 6 : v8::Local<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
633 18 : CHECK(CompileRun("JSON.stringify(obj)")
634 : ->Equals(env.local(), expected)
635 6 : .FromJust());
636 6 : }
637 :
638 :
639 : static v8::Local<v8::Context> expected_current_context;
640 :
641 :
642 120 : static void check_contexts(const v8::FunctionCallbackInfo<v8::Value>& info) {
643 60 : ApiTestFuzzer::Fuzz();
644 120 : CHECK(expected_current_context == info.GetIsolate()->GetCurrentContext());
645 60 : }
646 :
647 :
648 25881 : THREADED_TEST(AccessorPropertyCrossContext) {
649 6 : LocalContext env;
650 6 : v8::Isolate* isolate = env->GetIsolate();
651 12 : v8::HandleScope scope(isolate);
652 : v8::Local<v8::Function> fun =
653 12 : v8::Function::New(env.local(), check_contexts).ToLocalChecked();
654 12 : LocalContext switch_context;
655 30 : CHECK(switch_context->Global()
656 : ->Set(switch_context.local(), v8_str("fun"), fun)
657 : .FromJust());
658 12 : v8::TryCatch try_catch(isolate);
659 6 : expected_current_context = env.local();
660 : CompileRun(
661 : "var o = Object.create(null, { n: { get:fun } });"
662 : "for (var i = 0; i < 10; i++) o.n;");
663 12 : CHECK(!try_catch.HasCaught());
664 6 : }
665 :
666 :
667 25881 : THREADED_TEST(GlobalObjectAccessor) {
668 6 : LocalContext env;
669 6 : v8::Isolate* isolate = env->GetIsolate();
670 12 : v8::HandleScope scope(isolate);
671 : CompileRun(
672 : "var set_value = 1;"
673 : "Object.defineProperty(this.__proto__, 'x', {"
674 : " get : function() { return this; },"
675 : " set : function() { set_value = this; }"
676 : "});"
677 : "function getter() { return x; }"
678 : "function setter() { x = 1; }");
679 :
680 : Local<Script> check_getter = v8_compile("getter()");
681 : Local<Script> check_setter = v8_compile("setter(); set_value");
682 :
683 : // Ensure that LoadGlobalICs in getter and StoreGlobalICs setter get
684 : // JSGlobalProxy as a receiver regardless of the current IC state and
685 : // the order in which ICs are executed.
686 66 : for (int i = 0; i < 10; i++) {
687 180 : CHECK(
688 : v8::Utils::OpenHandle(*check_getter->Run(env.local()).ToLocalChecked())
689 : ->IsJSGlobalProxy());
690 : }
691 60 : for (int i = 0; i < 10; i++) {
692 180 : CHECK(
693 : v8::Utils::OpenHandle(*check_setter->Run(env.local()).ToLocalChecked())
694 : ->IsJSGlobalProxy());
695 : }
696 60 : for (int i = 0; i < 10; i++) {
697 180 : CHECK(
698 : v8::Utils::OpenHandle(*check_getter->Run(env.local()).ToLocalChecked())
699 : ->IsJSGlobalProxy());
700 180 : CHECK(
701 : v8::Utils::OpenHandle(*check_setter->Run(env.local()).ToLocalChecked())
702 : ->IsJSGlobalProxy());
703 6 : }
704 6 : }
705 :
706 :
707 12 : static void EmptyGetter(Local<Name> name,
708 : const v8::PropertyCallbackInfo<v8::Value>& info) {
709 12 : ApiTestFuzzer::Fuzz();
710 12 : }
711 :
712 :
713 6 : static void OneProperty(Local<String> name,
714 : const v8::PropertyCallbackInfo<v8::Value>& info) {
715 6 : ApiTestFuzzer::Fuzz();
716 6 : info.GetReturnValue().Set(v8_num(1));
717 6 : }
718 :
719 :
720 25881 : THREADED_TEST(Regress433458) {
721 6 : LocalContext env;
722 6 : v8::Isolate* isolate = env->GetIsolate();
723 12 : v8::HandleScope scope(isolate);
724 6 : v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
725 6 : obj->SetHandler(v8::NamedPropertyHandlerConfiguration(EmptyGetter));
726 6 : obj->SetNativeDataProperty(v8_str("prop"), OneProperty);
727 36 : CHECK(env->Global()
728 : ->Set(env.local(), v8_str("obj"),
729 : obj->NewInstance(env.local()).ToLocalChecked())
730 : .FromJust());
731 : CompileRun(
732 : "Object.defineProperty(obj, 'prop', { writable: false });"
733 6 : "Object.defineProperty(obj, 'prop', { writable: true });");
734 6 : }
735 :
736 :
737 : static bool security_check_value = false;
738 :
739 125 : static bool SecurityTestCallback(Local<v8::Context> accessing_context,
740 : Local<v8::Object> accessed_object,
741 : Local<v8::Value> data) {
742 125 : return security_check_value;
743 : }
744 :
745 :
746 25880 : TEST(PrototypeGetterAccessCheck) {
747 5 : i::FLAG_allow_natives_syntax = true;
748 5 : LocalContext env;
749 5 : v8::Isolate* isolate = env->GetIsolate();
750 10 : v8::HandleScope scope(isolate);
751 5 : auto fun_templ = v8::FunctionTemplate::New(isolate);
752 5 : auto getter_templ = v8::FunctionTemplate::New(isolate, handle_property);
753 5 : getter_templ->SetAcceptAnyReceiver(false);
754 10 : fun_templ->InstanceTemplate()->SetAccessorProperty(v8_str("foo"),
755 15 : getter_templ);
756 5 : auto obj_templ = v8::ObjectTemplate::New(isolate);
757 5 : obj_templ->SetAccessCheckCallback(SecurityTestCallback);
758 30 : CHECK(env->Global()
759 : ->Set(env.local(), v8_str("Fun"),
760 : fun_templ->GetFunction(env.local()).ToLocalChecked())
761 : .FromJust());
762 30 : CHECK(env->Global()
763 : ->Set(env.local(), v8_str("obj"),
764 : obj_templ->NewInstance(env.local()).ToLocalChecked())
765 : .FromJust());
766 30 : CHECK(env->Global()
767 : ->Set(env.local(), v8_str("obj2"),
768 : obj_templ->NewInstance(env.local()).ToLocalChecked())
769 : .FromJust());
770 :
771 5 : security_check_value = true;
772 : CompileRun("var proto = new Fun();");
773 : CompileRun("obj.__proto__ = proto;");
774 5 : ExpectInt32("proto.foo", 907);
775 :
776 : // Test direct.
777 5 : security_check_value = true;
778 5 : ExpectInt32("obj.foo", 907);
779 5 : security_check_value = false;
780 : {
781 5 : v8::TryCatch try_catch(isolate);
782 : CompileRun("obj.foo");
783 5 : CHECK(try_catch.HasCaught());
784 : }
785 :
786 : // Test through call.
787 5 : security_check_value = true;
788 5 : ExpectInt32("proto.__lookupGetter__('foo').call(obj)", 907);
789 5 : security_check_value = false;
790 : {
791 5 : v8::TryCatch try_catch(isolate);
792 : CompileRun("proto.__lookupGetter__('foo').call(obj)");
793 5 : CHECK(try_catch.HasCaught());
794 : }
795 :
796 : // Test ics.
797 : CompileRun(
798 : "function f() {"
799 : " var x;"
800 : " for (var i = 0; i < 4; i++) {"
801 : " x = obj.foo;"
802 : " }"
803 : " return x;"
804 : "}");
805 :
806 5 : security_check_value = true;
807 5 : ExpectInt32("f()", 907);
808 5 : security_check_value = false;
809 : {
810 5 : v8::TryCatch try_catch(isolate);
811 : CompileRun("f();");
812 5 : CHECK(try_catch.HasCaught());
813 : }
814 :
815 : // Test TurboFan.
816 : CompileRun("%OptimizeFunctionOnNextCall(f);");
817 :
818 5 : security_check_value = true;
819 5 : ExpectInt32("f()", 907);
820 5 : security_check_value = false;
821 : {
822 5 : v8::TryCatch try_catch(isolate);
823 : CompileRun("f();");
824 5 : CHECK(try_catch.HasCaught());
825 5 : }
826 5 : }
827 :
828 15 : static void CheckReceiver(Local<String> name,
829 : const v8::PropertyCallbackInfo<v8::Value>& info) {
830 15 : CHECK(info.This()->IsObject());
831 15 : }
832 :
833 25880 : TEST(Regress609134) {
834 5 : LocalContext env;
835 5 : v8::Isolate* isolate = env->GetIsolate();
836 10 : v8::HandleScope scope(isolate);
837 5 : auto fun_templ = v8::FunctionTemplate::New(isolate);
838 10 : fun_templ->InstanceTemplate()->SetNativeDataProperty(v8_str("foo"),
839 15 : CheckReceiver);
840 :
841 30 : CHECK(env->Global()
842 : ->Set(env.local(), v8_str("Fun"),
843 : fun_templ->GetFunction(env.local()).ToLocalChecked())
844 : .FromJust());
845 :
846 : CompileRun(
847 : "var f = new Fun();"
848 : "Number.prototype.__proto__ = f;"
849 : "var a = 42;"
850 5 : "for (var i = 0; i<3; i++) { a.foo; }");
851 5 : }
852 :
853 25880 : TEST(ObjectSetLazyDataProperty) {
854 5 : LocalContext env;
855 5 : v8::Isolate* isolate = env->GetIsolate();
856 10 : v8::HandleScope scope(isolate);
857 5 : v8::Local<v8::Object> obj = v8::Object::New(isolate);
858 25 : CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
859 :
860 : // Despite getting the property multiple times, the getter should only be
861 : // called once and data property reads should continue to produce the same
862 : // value.
863 : static int getter_call_count;
864 5 : getter_call_count = 0;
865 : auto result = obj->SetLazyDataProperty(
866 : env.local(), v8_str("foo"),
867 5 : [](Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
868 5 : getter_call_count++;
869 : info.GetReturnValue().Set(getter_call_count);
870 15 : });
871 5 : CHECK(result.FromJust());
872 5 : CHECK_EQ(0, getter_call_count);
873 10 : for (int i = 0; i < 2; i++) {
874 10 : ExpectInt32("obj.foo", 1);
875 10 : CHECK_EQ(1, getter_call_count);
876 : }
877 :
878 : // Setting should overwrite the data property.
879 : result = obj->SetLazyDataProperty(
880 : env.local(), v8_str("bar"),
881 0 : [](Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
882 0 : CHECK(false);
883 10 : });
884 5 : CHECK(result.FromJust());
885 10 : ExpectInt32("obj.bar = -1; obj.bar;", -1);
886 77630 : }
|