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 
handle_property(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
handle_property_2(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
handle_property(const v8::FunctionCallbackInfo<v8::Value> & info)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 
THREADED_TEST(PropertyHandler)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 
GetIntValue(Local<String> property,const v8::PropertyCallbackInfo<v8::Value> & info)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 
SetIntValue(Local<String> property,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)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 
THREADED_TEST(GlobalVariableAccess)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>
XGetter(const Info & info,int offset)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 
XGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
XGetter(const v8::FunctionCallbackInfo<v8::Value> & info)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>
XSetter(Local<Value> value,const Info & info,int offset)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 
XSetter(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)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 
XSetter(const v8::FunctionCallbackInfo<v8::Value> & info)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 
THREADED_TEST(AccessorIC)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>
HandleAllocatingGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
THREADED_TEST(HandleScopePop)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 
CheckAccessorArgsCorrect(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
THREADED_TEST(DirectCall)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 
EmptyGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
THREADED_TEST(EmptyResult)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 
THREADED_TEST(NoReuseRegress)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 
ThrowingGetAccessor(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
ThrowingSetAccessor(Local<String> name,Local<Value> value,const v8::PropertyCallbackInfo<void> & info)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 
THREADED_TEST(Regress1054726)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 
AllocGetter(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
THREADED_TEST(Gc)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 
StackCheck(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
THREADED_TEST(StackIteration)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 
AllocateHandles(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
THREADED_TEST(HandleScopeSegment)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 
JSONStringifyEnumerator(const v8::PropertyCallbackInfo<v8::Array> & info)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 
JSONStringifyGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)586 void JSONStringifyGetter(Local<Name> name,
587                          const v8::PropertyCallbackInfo<v8::Value>& info) {
588   info.GetReturnValue().Set(v8_str("crbug-161028"));
589 }
590 
591 
THREADED_TEST(JSONStringifyNamedInterceptorObject)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 
check_contexts(const v8::FunctionCallbackInfo<v8::Value> & info)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 
THREADED_TEST(AccessorPropertyCrossContext)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 
THREADED_TEST(GlobalObjectAccessor)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 
EmptyGetter(Local<Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)657 static void EmptyGetter(Local<Name> name,
658                         const v8::PropertyCallbackInfo<v8::Value>& info) {
659   ApiTestFuzzer::Fuzz();
660 }
661 
662 
OneProperty(Local<String> name,const v8::PropertyCallbackInfo<v8::Value> & info)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 
THREADED_TEST(Regress433458)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 
SecurityTestCallback(Local<v8::Context> accessing_context,Local<v8::Object> accessed_object)690 static bool SecurityTestCallback(Local<v8::Context> accessing_context,
691                                  Local<v8::Object> accessed_object) {
692   return security_check_value;
693 }
694 
695 
TEST(PrototypeGetterAccessCheck)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