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
37using ::v8::ObjectTemplate;
38using ::v8::Value;
39using ::v8::Context;
40using ::v8::Local;
41using ::v8::Name;
42using ::v8::String;
43using ::v8::Script;
44using ::v8::Function;
45using ::v8::Extension;
46
47static 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
53static 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
60static 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
67THREADED_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
120static 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
129static 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
137int foo, bar, baz;
138
139THREADED_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
162static int x_register[2] = {0, 0};
163static v8::Local<v8::Object> x_receiver;
164static v8::Local<v8::Object> x_holder;
165
166template<class Info>
167static 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
177static 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
185static 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
193template<class Info>
194static 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
207static void XSetter(Local<String> name,
208                    Local<Value> value,
209                    const v8::PropertyCallbackInfo<void>& info) {
210  XSetter(value, info, 0);
211}
212
213
214static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
215  CHECK_EQ(1, info.Length());
216  XSetter(info[0], info, 1);
217}
218
219
220THREADED_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
266template <int C>
267static 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
282THREADED_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
308static 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
332THREADED_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
352static 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
361THREADED_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
380THREADED_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
421static 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
429static void ThrowingSetAccessor(Local<String> name,
430                                Local<Value> value,
431                                const v8::PropertyCallbackInfo<void>& info) {
432  info.GetIsolate()->ThrowException(value);
433}
434
435
436THREADED_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
477static 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
484THREADED_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
506static 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
521THREADED_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
545static 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
554THREADED_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
578void 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
586void JSONStringifyGetter(Local<Name> name,
587                         const v8::PropertyCallbackInfo<v8::Value>& info) {
588  info.GetReturnValue().Set(v8_str("crbug-161028"));
589}
590
591
592THREADED_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
611static v8::Local<v8::Context> expected_current_context;
612
613
614static void check_contexts(const v8::FunctionCallbackInfo<v8::Value>& info) {
615  ApiTestFuzzer::Fuzz();
616  CHECK(expected_current_context == info.GetIsolate()->GetCurrentContext());
617}
618
619
620THREADED_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
639THREADED_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
657static void EmptyGetter(Local<Name> name,
658                        const v8::PropertyCallbackInfo<v8::Value>& info) {
659  ApiTestFuzzer::Fuzz();
660}
661
662
663static 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
670THREADED_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
687static bool security_check_value = false;
688
689static bool SecurityTestCallback(Local<v8::Context> accessing_context,
690                                 Local<v8::Object> accessed_object,
691                                 Local<v8::Value> data) {
692  return security_check_value;
693}
694
695
696TEST(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
778static void CheckReceiver(Local<String> name,
779                          const v8::PropertyCallbackInfo<v8::Value>& info) {
780  CHECK(info.This()->IsObject());
781}
782
783TEST(Regress609134) {
784  LocalContext env;
785  v8::Isolate* isolate = env->GetIsolate();
786  v8::HandleScope scope(isolate);
787  auto fun_templ = v8::FunctionTemplate::New(isolate);
788  fun_templ->InstanceTemplate()->SetNativeDataProperty(v8_str("foo"),
789                                                       CheckReceiver);
790
791  CHECK(env->Global()
792            ->Set(env.local(), v8_str("Fun"),
793                  fun_templ->GetFunction(env.local()).ToLocalChecked())
794            .FromJust());
795
796  CompileRun(
797      "var f = new Fun();"
798      "Number.prototype.__proto__ = f;"
799      "var a = 42;"
800      "for (var i = 0; i<3; i++) { a.foo; }");
801}
802