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