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.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 static void handle_property(Local<String> name, 48 const v8::PropertyCallbackInfo<v8::Value>& info) { 49 ApiTestFuzzer::Fuzz(); 50 info.GetReturnValue().Set(v8_num(900)); 51 } 52 53 static void handle_property_2(Local<String> name, 54 const v8::PropertyCallbackInfo<v8::Value>& info) { 55 ApiTestFuzzer::Fuzz(); 56 info.GetReturnValue().Set(v8_num(902)); 57 } 58 59 60 static void handle_property(const v8::FunctionCallbackInfo<v8::Value>& info) { 61 ApiTestFuzzer::Fuzz(); 62 CHECK_EQ(0, info.Length()); 63 info.GetReturnValue().Set(v8_num(907)); 64 } 65 66 67 THREADED_TEST(PropertyHandler) { 68 LocalContext env; 69 v8::Isolate* isolate = env->GetIsolate(); 70 v8::HandleScope scope(isolate); 71 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate); 72 fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property); 73 Local<v8::FunctionTemplate> getter_templ = 74 v8::FunctionTemplate::New(isolate, handle_property); 75 getter_templ->SetLength(0); 76 fun_templ-> 77 InstanceTemplate()->SetAccessorProperty(v8_str("bar"), getter_templ); 78 fun_templ->InstanceTemplate()-> 79 SetNativeDataProperty(v8_str("instance_foo"), handle_property); 80 fun_templ->SetNativeDataProperty(v8_str("object_foo"), handle_property_2); 81 Local<Function> fun = fun_templ->GetFunction(env.local()).ToLocalChecked(); 82 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 CHECK_EQ(900, getter->Run(env.local()) 88 .ToLocalChecked() 89 ->Int32Value(env.local()) 90 .FromJust()); 91 setter = v8_compile("obj.instance_foo = 901;"); 92 CHECK_EQ(901, setter->Run(env.local()) 93 .ToLocalChecked() 94 ->Int32Value(env.local()) 95 .FromJust()); 96 getter = v8_compile("obj.bar;"); 97 CHECK_EQ(907, getter->Run(env.local()) 98 .ToLocalChecked() 99 ->Int32Value(env.local()) 100 .FromJust()); 101 setter = v8_compile("obj.bar = 908;"); 102 CHECK_EQ(908, setter->Run(env.local()) 103 .ToLocalChecked() 104 ->Int32Value(env.local()) 105 .FromJust()); 106 // check function static accessors 107 getter = v8_compile("Fun.object_foo;"); 108 CHECK_EQ(902, getter->Run(env.local()) 109 .ToLocalChecked() 110 ->Int32Value(env.local()) 111 .FromJust()); 112 setter = v8_compile("Fun.object_foo = 903;"); 113 CHECK_EQ(903, setter->Run(env.local()) 114 .ToLocalChecked() 115 ->Int32Value(env.local()) 116 .FromJust()); 117 } 118 119 120 static void GetIntValue(Local<String> property, 121 const v8::PropertyCallbackInfo<v8::Value>& info) { 122 ApiTestFuzzer::Fuzz(); 123 int* value = 124 static_cast<int*>(v8::Local<v8::External>::Cast(info.Data())->Value()); 125 info.GetReturnValue().Set(v8_num(*value)); 126 } 127 128 129 static void SetIntValue(Local<String> property, 130 Local<Value> value, 131 const v8::PropertyCallbackInfo<void>& info) { 132 int* field = 133 static_cast<int*>(v8::Local<v8::External>::Cast(info.Data())->Value()); 134 *field = value->Int32Value(info.GetIsolate()->GetCurrentContext()).FromJust(); 135 } 136 137 int foo, bar, baz; 138 139 THREADED_TEST(GlobalVariableAccess) { 140 foo = 0; 141 bar = -4; 142 baz = 10; 143 v8::Isolate* isolate = CcTest::isolate(); 144 v8::HandleScope scope(isolate); 145 v8::Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); 146 templ->InstanceTemplate()->SetAccessor( 147 v8_str("foo"), GetIntValue, SetIntValue, 148 v8::External::New(isolate, &foo)); 149 templ->InstanceTemplate()->SetAccessor( 150 v8_str("bar"), GetIntValue, SetIntValue, 151 v8::External::New(isolate, &bar)); 152 templ->InstanceTemplate()->SetAccessor( 153 v8_str("baz"), GetIntValue, SetIntValue, 154 v8::External::New(isolate, &baz)); 155 LocalContext env(0, templ->InstanceTemplate()); 156 v8_compile("foo = (++bar) + baz")->Run(env.local()).ToLocalChecked(); 157 CHECK_EQ(bar, -3); 158 CHECK_EQ(foo, 7); 159 } 160 161 162 static int x_register[2] = {0, 0}; 163 static v8::Local<v8::Object> x_receiver; 164 static v8::Local<v8::Object> x_holder; 165 166 template<class Info> 167 static void XGetter(const Info& info, int offset) { 168 ApiTestFuzzer::Fuzz(); 169 v8::Isolate* isolate = CcTest::isolate(); 170 CHECK_EQ(isolate, info.GetIsolate()); 171 CHECK( 172 x_receiver->Equals(isolate->GetCurrentContext(), info.This()).FromJust()); 173 info.GetReturnValue().Set(v8_num(x_register[offset])); 174 } 175 176 177 static void XGetter(Local<String> name, 178 const v8::PropertyCallbackInfo<v8::Value>& info) { 179 CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder()) 180 .FromJust()); 181 XGetter(info, 0); 182 } 183 184 185 static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) { 186 CHECK( 187 x_receiver->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder()) 188 .FromJust()); 189 XGetter(info, 1); 190 } 191 192 193 template<class Info> 194 static void XSetter(Local<Value> value, const Info& info, int offset) { 195 v8::Isolate* isolate = CcTest::isolate(); 196 CHECK_EQ(isolate, info.GetIsolate()); 197 CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.This()) 198 .FromJust()); 199 CHECK(x_holder->Equals(info.GetIsolate()->GetCurrentContext(), info.Holder()) 200 .FromJust()); 201 x_register[offset] = 202 value->Int32Value(info.GetIsolate()->GetCurrentContext()).FromJust(); 203 info.GetReturnValue().Set(v8_num(-1)); 204 } 205 206 207 static void XSetter(Local<String> name, 208 Local<Value> value, 209 const v8::PropertyCallbackInfo<void>& info) { 210 XSetter(value, info, 0); 211 } 212 213 214 static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) { 215 CHECK_EQ(1, info.Length()); 216 XSetter(info[0], info, 1); 217 } 218 219 220 THREADED_TEST(AccessorIC) { 221 LocalContext context; 222 v8::Isolate* isolate = context->GetIsolate(); 223 v8::HandleScope scope(isolate); 224 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 225 obj->SetAccessor(v8_str("x0"), XGetter, XSetter); 226 obj->SetAccessorProperty(v8_str("x1"), 227 v8::FunctionTemplate::New(isolate, XGetter), 228 v8::FunctionTemplate::New(isolate, XSetter)); 229 x_holder = obj->NewInstance(context.local()).ToLocalChecked(); 230 CHECK(context->Global() 231 ->Set(context.local(), v8_str("holder"), x_holder) 232 .FromJust()); 233 x_receiver = v8::Object::New(isolate); 234 CHECK(context->Global() 235 ->Set(context.local(), v8_str("obj"), x_receiver) 236 .FromJust()); 237 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast( 238 CompileRun("obj.__proto__ = holder;" 239 "var result = [];" 240 "var key_0 = 'x0';" 241 "var key_1 = 'x1';" 242 "for (var j = 0; j < 10; j++) {" 243 " var i = 4*j;" 244 " result.push(holder.x0 = i);" 245 " result.push(obj.x0);" 246 " result.push(holder.x1 = i + 1);" 247 " result.push(obj.x1);" 248 " result.push(holder[key_0] = i + 2);" 249 " result.push(obj[key_0]);" 250 " result.push(holder[key_1] = i + 3);" 251 " result.push(obj[key_1]);" 252 "}" 253 "result")); 254 CHECK_EQ(80u, array->Length()); 255 for (int i = 0; i < 80; i++) { 256 v8::Local<Value> entry = 257 array->Get(context.local(), v8::Integer::New(isolate, i)) 258 .ToLocalChecked(); 259 CHECK(v8::Integer::New(isolate, i / 2) 260 ->Equals(context.local(), entry) 261 .FromJust()); 262 } 263 } 264 265 266 template <int C> 267 static void HandleAllocatingGetter( 268 Local<String> name, 269 const v8::PropertyCallbackInfo<v8::Value>& info) { 270 ApiTestFuzzer::Fuzz(); 271 for (int i = 0; i < C; i++) { 272 v8::String::NewFromUtf8(info.GetIsolate(), "foo", 273 v8::NewStringType::kNormal) 274 .ToLocalChecked(); 275 } 276 info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "foo", 277 v8::NewStringType::kNormal) 278 .ToLocalChecked()); 279 } 280 281 282 THREADED_TEST(HandleScopePop) { 283 LocalContext context; 284 v8::Isolate* isolate = context->GetIsolate(); 285 v8::HandleScope scope(isolate); 286 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 287 obj->SetAccessor(v8_str("one"), HandleAllocatingGetter<1>); 288 obj->SetAccessor(v8_str("many"), HandleAllocatingGetter<1024>); 289 v8::Local<v8::Object> inst = 290 obj->NewInstance(context.local()).ToLocalChecked(); 291 CHECK( 292 context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust()); 293 int count_before = 294 i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate)); 295 { 296 v8::HandleScope scope(isolate); 297 CompileRun( 298 "for (var i = 0; i < 1000; i++) {" 299 " obj.one;" 300 " obj.many;" 301 "}"); 302 } 303 int count_after = 304 i::HandleScope::NumberOfHandles(reinterpret_cast<i::Isolate*>(isolate)); 305 CHECK_EQ(count_before, count_after); 306 } 307 308 static void CheckAccessorArgsCorrect( 309 Local<String> name, 310 const v8::PropertyCallbackInfo<v8::Value>& info) { 311 CHECK(info.GetIsolate() == CcTest::isolate()); 312 CHECK(info.This() == info.Holder()); 313 CHECK(info.Data() 314 ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data")) 315 .FromJust()); 316 ApiTestFuzzer::Fuzz(); 317 CHECK(info.GetIsolate() == CcTest::isolate()); 318 CHECK(info.This() == info.Holder()); 319 CHECK(info.Data() 320 ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data")) 321 .FromJust()); 322 CcTest::heap()->CollectAllGarbage(); 323 CHECK(info.GetIsolate() == CcTest::isolate()); 324 CHECK(info.This() == info.Holder()); 325 CHECK(info.Data() 326 ->Equals(info.GetIsolate()->GetCurrentContext(), v8_str("data")) 327 .FromJust()); 328 info.GetReturnValue().Set(17); 329 } 330 331 332 THREADED_TEST(DirectCall) { 333 LocalContext context; 334 v8::Isolate* isolate = context->GetIsolate(); 335 v8::HandleScope scope(isolate); 336 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 337 obj->SetAccessor(v8_str("xxx"), CheckAccessorArgsCorrect, NULL, 338 v8_str("data")); 339 v8::Local<v8::Object> inst = 340 obj->NewInstance(context.local()).ToLocalChecked(); 341 CHECK( 342 context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust()); 343 Local<Script> scr = 344 v8::Script::Compile(context.local(), v8_str("obj.xxx")).ToLocalChecked(); 345 for (int i = 0; i < 10; i++) { 346 Local<Value> result = scr->Run(context.local()).ToLocalChecked(); 347 CHECK(!result.IsEmpty()); 348 CHECK_EQ(17, result->Int32Value(context.local()).FromJust()); 349 } 350 } 351 352 static void EmptyGetter(Local<String> name, 353 const v8::PropertyCallbackInfo<v8::Value>& info) { 354 CheckAccessorArgsCorrect(name, info); 355 ApiTestFuzzer::Fuzz(); 356 CheckAccessorArgsCorrect(name, info); 357 info.GetReturnValue().Set(v8::Local<v8::Value>()); 358 } 359 360 361 THREADED_TEST(EmptyResult) { 362 LocalContext context; 363 v8::Isolate* isolate = context->GetIsolate(); 364 v8::HandleScope scope(isolate); 365 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 366 obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8_str("data")); 367 v8::Local<v8::Object> inst = 368 obj->NewInstance(context.local()).ToLocalChecked(); 369 CHECK( 370 context->Global()->Set(context.local(), v8_str("obj"), inst).FromJust()); 371 Local<Script> scr = 372 v8::Script::Compile(context.local(), v8_str("obj.xxx")).ToLocalChecked(); 373 for (int i = 0; i < 10; i++) { 374 Local<Value> result = scr->Run(context.local()).ToLocalChecked(); 375 CHECK(result == v8::Undefined(isolate)); 376 } 377 } 378 379 380 THREADED_TEST(NoReuseRegress) { 381 // Check that the IC generated for the one test doesn't get reused 382 // for the other. 383 v8::Isolate* isolate = CcTest::isolate(); 384 v8::HandleScope scope(isolate); 385 { 386 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 387 obj->SetAccessor(v8_str("xxx"), EmptyGetter, NULL, v8_str("data")); 388 LocalContext context; 389 v8::Local<v8::Object> inst = 390 obj->NewInstance(context.local()).ToLocalChecked(); 391 CHECK(context->Global() 392 ->Set(context.local(), v8_str("obj"), inst) 393 .FromJust()); 394 Local<Script> scr = v8::Script::Compile(context.local(), v8_str("obj.xxx")) 395 .ToLocalChecked(); 396 for (int i = 0; i < 2; i++) { 397 Local<Value> result = scr->Run(context.local()).ToLocalChecked(); 398 CHECK(result == v8::Undefined(isolate)); 399 } 400 } 401 { 402 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 403 obj->SetAccessor(v8_str("xxx"), CheckAccessorArgsCorrect, NULL, 404 v8_str("data")); 405 LocalContext context; 406 v8::Local<v8::Object> inst = 407 obj->NewInstance(context.local()).ToLocalChecked(); 408 CHECK(context->Global() 409 ->Set(context.local(), v8_str("obj"), inst) 410 .FromJust()); 411 Local<Script> scr = v8::Script::Compile(context.local(), v8_str("obj.xxx")) 412 .ToLocalChecked(); 413 for (int i = 0; i < 10; i++) { 414 Local<Value> result = scr->Run(context.local()).ToLocalChecked(); 415 CHECK(!result.IsEmpty()); 416 CHECK_EQ(17, result->Int32Value(context.local()).FromJust()); 417 } 418 } 419 } 420 421 static void ThrowingGetAccessor( 422 Local<String> name, 423 const v8::PropertyCallbackInfo<v8::Value>& info) { 424 ApiTestFuzzer::Fuzz(); 425 info.GetIsolate()->ThrowException(v8_str("g")); 426 } 427 428 429 static void ThrowingSetAccessor(Local<String> name, 430 Local<Value> value, 431 const v8::PropertyCallbackInfo<void>& info) { 432 info.GetIsolate()->ThrowException(value); 433 } 434 435 436 THREADED_TEST(Regress1054726) { 437 LocalContext env; 438 v8::Isolate* isolate = env->GetIsolate(); 439 v8::HandleScope scope(isolate); 440 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 441 obj->SetAccessor(v8_str("x"), 442 ThrowingGetAccessor, 443 ThrowingSetAccessor, 444 Local<Value>()); 445 446 CHECK(env->Global() 447 ->Set(env.local(), v8_str("obj"), 448 obj->NewInstance(env.local()).ToLocalChecked()) 449 .FromJust()); 450 451 // Use the throwing property setter/getter in a loop to force 452 // the accessor ICs to be initialized. 453 v8::Local<Value> result; 454 result = Script::Compile(env.local(), 455 v8_str("var result = '';" 456 "for (var i = 0; i < 5; i++) {" 457 " try { obj.x; } catch (e) { result += e; }" 458 "}; result")) 459 .ToLocalChecked() 460 ->Run(env.local()) 461 .ToLocalChecked(); 462 CHECK(v8_str("ggggg")->Equals(env.local(), result).FromJust()); 463 464 result = 465 Script::Compile(env.local(), 466 v8_str("var result = '';" 467 "for (var i = 0; i < 5; i++) {" 468 " try { obj.x = i; } catch (e) { result += e; }" 469 "}; result")) 470 .ToLocalChecked() 471 ->Run(env.local()) 472 .ToLocalChecked(); 473 CHECK(v8_str("01234")->Equals(env.local(), result).FromJust()); 474 } 475 476 477 static void AllocGetter(Local<String> name, 478 const v8::PropertyCallbackInfo<v8::Value>& info) { 479 ApiTestFuzzer::Fuzz(); 480 info.GetReturnValue().Set(v8::Array::New(info.GetIsolate(), 1000)); 481 } 482 483 484 THREADED_TEST(Gc) { 485 LocalContext env; 486 v8::Isolate* isolate = env->GetIsolate(); 487 v8::HandleScope scope(isolate); 488 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 489 obj->SetAccessor(v8_str("xxx"), AllocGetter); 490 CHECK(env->Global() 491 ->Set(env.local(), v8_str("obj"), 492 obj->NewInstance(env.local()).ToLocalChecked()) 493 .FromJust()); 494 Script::Compile(env.local(), v8_str("var last = [];" 495 "for (var i = 0; i < 2048; i++) {" 496 " var result = obj.xxx;" 497 " result[0] = last;" 498 " last = result;" 499 "}")) 500 .ToLocalChecked() 501 ->Run(env.local()) 502 .ToLocalChecked(); 503 } 504 505 506 static void StackCheck(Local<String> name, 507 const v8::PropertyCallbackInfo<v8::Value>& info) { 508 i::StackFrameIterator iter(reinterpret_cast<i::Isolate*>(info.GetIsolate())); 509 for (int i = 0; !iter.done(); i++) { 510 i::StackFrame* frame = iter.frame(); 511 CHECK(i != 0 || (frame->type() == i::StackFrame::EXIT)); 512 i::Code* code = frame->LookupCode(); 513 CHECK(code->IsCode()); 514 i::Address pc = frame->pc(); 515 CHECK(code->contains(pc)); 516 iter.Advance(); 517 } 518 } 519 520 521 THREADED_TEST(StackIteration) { 522 LocalContext env; 523 v8::Isolate* isolate = env->GetIsolate(); 524 v8::HandleScope scope(isolate); 525 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 526 i::StringStream::ClearMentionedObjectCache( 527 reinterpret_cast<i::Isolate*>(isolate)); 528 obj->SetAccessor(v8_str("xxx"), StackCheck); 529 CHECK(env->Global() 530 ->Set(env.local(), v8_str("obj"), 531 obj->NewInstance(env.local()).ToLocalChecked()) 532 .FromJust()); 533 Script::Compile(env.local(), v8_str("function foo() {" 534 " return obj.xxx;" 535 "}" 536 "for (var i = 0; i < 100; i++) {" 537 " foo();" 538 "}")) 539 .ToLocalChecked() 540 ->Run(env.local()) 541 .ToLocalChecked(); 542 } 543 544 545 static void AllocateHandles(Local<String> name, 546 const v8::PropertyCallbackInfo<v8::Value>& info) { 547 for (int i = 0; i < i::kHandleBlockSize + 1; i++) { 548 v8::Local<v8::Value>::New(info.GetIsolate(), name); 549 } 550 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 100)); 551 } 552 553 554 THREADED_TEST(HandleScopeSegment) { 555 // Check that we can return values past popping of handle scope 556 // segments. 557 LocalContext env; 558 v8::Isolate* isolate = env->GetIsolate(); 559 v8::HandleScope scope(isolate); 560 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 561 obj->SetAccessor(v8_str("xxx"), AllocateHandles); 562 CHECK(env->Global() 563 ->Set(env.local(), v8_str("obj"), 564 obj->NewInstance(env.local()).ToLocalChecked()) 565 .FromJust()); 566 v8::Local<v8::Value> result = 567 Script::Compile(env.local(), v8_str("var result;" 568 "for (var i = 0; i < 4; i++)" 569 " result = obj.xxx;" 570 "result;")) 571 .ToLocalChecked() 572 ->Run(env.local()) 573 .ToLocalChecked(); 574 CHECK_EQ(100, result->Int32Value(env.local()).FromJust()); 575 } 576 577 578 void JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { 579 v8::Local<v8::Array> array = v8::Array::New(info.GetIsolate(), 1); 580 CHECK(array->Set(info.GetIsolate()->GetCurrentContext(), 0, v8_str("regress")) 581 .FromJust()); 582 info.GetReturnValue().Set(array); 583 } 584 585 586 void JSONStringifyGetter(Local<Name> name, 587 const v8::PropertyCallbackInfo<v8::Value>& info) { 588 info.GetReturnValue().Set(v8_str("crbug-161028")); 589 } 590 591 592 THREADED_TEST(JSONStringifyNamedInterceptorObject) { 593 LocalContext env; 594 v8::Isolate* isolate = env->GetIsolate(); 595 v8::HandleScope scope(isolate); 596 597 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 598 obj->SetHandler(v8::NamedPropertyHandlerConfiguration( 599 JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator)); 600 CHECK(env->Global() 601 ->Set(env.local(), v8_str("obj"), 602 obj->NewInstance(env.local()).ToLocalChecked()) 603 .FromJust()); 604 v8::Local<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}"); 605 CHECK(CompileRun("JSON.stringify(obj)") 606 ->Equals(env.local(), expected) 607 .FromJust()); 608 } 609 610 611 static v8::Local<v8::Context> expected_current_context; 612 613 614 static void check_contexts(const v8::FunctionCallbackInfo<v8::Value>& info) { 615 ApiTestFuzzer::Fuzz(); 616 CHECK(expected_current_context == info.GetIsolate()->GetCurrentContext()); 617 } 618 619 620 THREADED_TEST(AccessorPropertyCrossContext) { 621 LocalContext env; 622 v8::Isolate* isolate = env->GetIsolate(); 623 v8::HandleScope scope(isolate); 624 v8::Local<v8::Function> fun = 625 v8::Function::New(env.local(), check_contexts).ToLocalChecked(); 626 LocalContext switch_context; 627 CHECK(switch_context->Global() 628 ->Set(switch_context.local(), v8_str("fun"), fun) 629 .FromJust()); 630 v8::TryCatch try_catch(isolate); 631 expected_current_context = env.local(); 632 CompileRun( 633 "var o = Object.create(null, { n: { get:fun } });" 634 "for (var i = 0; i < 10; i++) o.n;"); 635 CHECK(!try_catch.HasCaught()); 636 } 637 638 639 THREADED_TEST(GlobalObjectAccessor) { 640 LocalContext env; 641 v8::Isolate* isolate = env->GetIsolate(); 642 v8::HandleScope scope(isolate); 643 CompileRun( 644 "var set_value = 1;" 645 "Object.defineProperty(this.__proto__, 'x', {" 646 " get : function() { return this; }," 647 " set : function() { set_value = this; }" 648 "});" 649 "function getter() { return x; }" 650 "function setter() { x = 1; }" 651 "for (var i = 0; i < 4; i++) { getter(); setter(); }"); 652 CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy()); 653 CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy()); 654 } 655 656 657 static void EmptyGetter(Local<Name> name, 658 const v8::PropertyCallbackInfo<v8::Value>& info) { 659 ApiTestFuzzer::Fuzz(); 660 } 661 662 663 static void OneProperty(Local<String> name, 664 const v8::PropertyCallbackInfo<v8::Value>& info) { 665 ApiTestFuzzer::Fuzz(); 666 info.GetReturnValue().Set(v8_num(1)); 667 } 668 669 670 THREADED_TEST(Regress433458) { 671 LocalContext env; 672 v8::Isolate* isolate = env->GetIsolate(); 673 v8::HandleScope scope(isolate); 674 v8::Local<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate); 675 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(EmptyGetter)); 676 obj->SetNativeDataProperty(v8_str("prop"), OneProperty); 677 CHECK(env->Global() 678 ->Set(env.local(), v8_str("obj"), 679 obj->NewInstance(env.local()).ToLocalChecked()) 680 .FromJust()); 681 CompileRun( 682 "Object.defineProperty(obj, 'prop', { writable: false });" 683 "Object.defineProperty(obj, 'prop', { writable: true });"); 684 } 685 686 687 static bool security_check_value = false; 688 689 690 static bool SecurityTestCallback(Local<v8::Context> accessing_context, 691 Local<v8::Object> accessed_object) { 692 return security_check_value; 693 } 694 695 696 TEST(PrototypeGetterAccessCheck) { 697 i::FLAG_allow_natives_syntax = true; 698 LocalContext env; 699 v8::Isolate* isolate = env->GetIsolate(); 700 v8::HandleScope scope(isolate); 701 auto fun_templ = v8::FunctionTemplate::New(isolate); 702 auto getter_templ = v8::FunctionTemplate::New(isolate, handle_property); 703 getter_templ->SetAcceptAnyReceiver(false); 704 fun_templ->InstanceTemplate()->SetAccessorProperty(v8_str("foo"), 705 getter_templ); 706 auto obj_templ = v8::ObjectTemplate::New(isolate); 707 obj_templ->SetAccessCheckCallback(SecurityTestCallback); 708 CHECK(env->Global() 709 ->Set(env.local(), v8_str("Fun"), 710 fun_templ->GetFunction(env.local()).ToLocalChecked()) 711 .FromJust()); 712 CHECK(env->Global() 713 ->Set(env.local(), v8_str("obj"), 714 obj_templ->NewInstance(env.local()).ToLocalChecked()) 715 .FromJust()); 716 CHECK(env->Global() 717 ->Set(env.local(), v8_str("obj2"), 718 obj_templ->NewInstance(env.local()).ToLocalChecked()) 719 .FromJust()); 720 721 security_check_value = true; 722 CompileRun("var proto = new Fun();"); 723 CompileRun("obj.__proto__ = proto;"); 724 ExpectInt32("proto.foo", 907); 725 726 // Test direct. 727 security_check_value = true; 728 ExpectInt32("obj.foo", 907); 729 security_check_value = false; 730 { 731 v8::TryCatch try_catch(isolate); 732 CompileRun("obj.foo"); 733 CHECK(try_catch.HasCaught()); 734 } 735 736 // Test through call. 737 security_check_value = true; 738 ExpectInt32("proto.__lookupGetter__('foo').call(obj)", 907); 739 security_check_value = false; 740 { 741 v8::TryCatch try_catch(isolate); 742 CompileRun("proto.__lookupGetter__('foo').call(obj)"); 743 CHECK(try_catch.HasCaught()); 744 } 745 746 // Test ics. 747 CompileRun( 748 "function f() {" 749 " var x;" 750 " for (var i = 0; i < 4; i++) {" 751 " x = obj.foo;" 752 " }" 753 " return x;" 754 "}"); 755 756 security_check_value = true; 757 ExpectInt32("f()", 907); 758 security_check_value = false; 759 { 760 v8::TryCatch try_catch(isolate); 761 CompileRun("f();"); 762 CHECK(try_catch.HasCaught()); 763 } 764 765 // Test crankshaft. 766 CompileRun("%OptimizeFunctionOnNextCall(f);"); 767 768 security_check_value = true; 769 ExpectInt32("f()", 907); 770 security_check_value = false; 771 { 772 v8::TryCatch try_catch(isolate); 773 CompileRun("f();"); 774 CHECK(try_catch.HasCaught()); 775 } 776 } 777