v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-strings.cc
Go to the documentation of this file.
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 
3 // Check that we can traverse very deep stacks of ConsStrings using
4 // StringInputBuffer. Check that Get(int) works on very deep stacks
5 // of ConsStrings. These operations may not be very fast, but they
6 // should be possible without getting errors due to too deep recursion.
7 
8 #include <stdlib.h>
9 
10 #include "v8.h"
11 
12 #include "api.h"
13 #include "factory.h"
14 #include "cctest.h"
15 #include "zone-inl.h"
16 
17 unsigned int seed = 123;
18 
19 static uint32_t gen() {
20  uint64_t z;
21  z = seed;
22  z *= 279470273;
23  z %= 4294967291U;
24  seed = static_cast<unsigned int>(z);
25  return static_cast<uint32_t>(seed >> 16);
26 }
27 
28 
29 using namespace v8::internal;
30 
32 
33 
34 static void InitializeVM() {
35  if (env.IsEmpty()) {
36  v8::HandleScope scope;
37  const char* extensions[] = { "v8/print" };
38  v8::ExtensionConfiguration config(1, extensions);
39  env = v8::Context::New(&config);
40  }
41  v8::HandleScope scope;
42  env->Enter();
43 }
44 
45 
46 static const int NUMBER_OF_BUILDING_BLOCKS = 128;
47 static const int DEEP_DEPTH = 8 * 1024;
48 static const int SUPER_DEEP_DEPTH = 80 * 1024;
49 
50 
52  public ZoneObject {
53  public:
54  explicit Resource(Vector<const uc16> string): data_(string.start()) {
55  length_ = string.length();
56  }
57  virtual const uint16_t* data() const { return data_; }
58  virtual size_t length() const { return length_; }
59 
60  private:
61  const uc16* data_;
62  size_t length_;
63 };
64 
65 
67  public ZoneObject {
68  public:
69  explicit AsciiResource(Vector<const char> string): data_(string.start()) {
70  length_ = string.length();
71  }
72  virtual const char* data() const { return data_; }
73  virtual size_t length() const { return length_; }
74 
75  private:
76  const char* data_;
77  size_t length_;
78 };
79 
80 
81 static void InitializeBuildingBlocks(
82  Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) {
83  // A list of pointers that we don't have any interest in cleaning up.
84  // If they are reachable from a root then leak detection won't complain.
85  Zone* zone = Isolate::Current()->zone();
86  for (int i = 0; i < NUMBER_OF_BUILDING_BLOCKS; i++) {
87  int len = gen() % 16;
88  if (len > 14) {
89  len += 1234;
90  }
91  switch (gen() % 4) {
92  case 0: {
93  uc16 buf[2000];
94  for (int j = 0; j < len; j++) {
95  buf[j] = gen() % 65536;
96  }
97  building_blocks[i] =
98  FACTORY->NewStringFromTwoByte(Vector<const uc16>(buf, len));
99  for (int j = 0; j < len; j++) {
100  CHECK_EQ(buf[j], building_blocks[i]->Get(j));
101  }
102  break;
103  }
104  case 1: {
105  char buf[2000];
106  for (int j = 0; j < len; j++) {
107  buf[j] = gen() % 128;
108  }
109  building_blocks[i] =
110  FACTORY->NewStringFromAscii(Vector<const char>(buf, len));
111  for (int j = 0; j < len; j++) {
112  CHECK_EQ(buf[j], building_blocks[i]->Get(j));
113  }
114  break;
115  }
116  case 2: {
117  uc16* buf = zone->NewArray<uc16>(len);
118  for (int j = 0; j < len; j++) {
119  buf[j] = gen() % 65536;
120  }
121  Resource* resource = new(zone) Resource(Vector<const uc16>(buf, len));
122  building_blocks[i] = FACTORY->NewExternalStringFromTwoByte(resource);
123  for (int j = 0; j < len; j++) {
124  CHECK_EQ(buf[j], building_blocks[i]->Get(j));
125  }
126  break;
127  }
128  case 3: {
129  char* buf = NewArray<char>(len);
130  for (int j = 0; j < len; j++) {
131  buf[j] = gen() % 128;
132  }
133  building_blocks[i] =
134  FACTORY->NewStringFromAscii(Vector<const char>(buf, len));
135  for (int j = 0; j < len; j++) {
136  CHECK_EQ(buf[j], building_blocks[i]->Get(j));
137  }
138  DeleteArray<char>(buf);
139  break;
140  }
141  }
142  }
143 }
144 
145 
146 static Handle<String> ConstructLeft(
147  Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
148  int depth) {
149  Handle<String> answer = FACTORY->NewStringFromAscii(CStrVector(""));
150  for (int i = 0; i < depth; i++) {
151  answer = FACTORY->NewConsString(
152  answer,
153  building_blocks[i % NUMBER_OF_BUILDING_BLOCKS]);
154  }
155  return answer;
156 }
157 
158 
159 static Handle<String> ConstructRight(
160  Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
161  int depth) {
162  Handle<String> answer = FACTORY->NewStringFromAscii(CStrVector(""));
163  for (int i = depth - 1; i >= 0; i--) {
164  answer = FACTORY->NewConsString(
165  building_blocks[i % NUMBER_OF_BUILDING_BLOCKS],
166  answer);
167  }
168  return answer;
169 }
170 
171 
172 static Handle<String> ConstructBalancedHelper(
173  Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS],
174  int from,
175  int to) {
176  CHECK(to > from);
177  if (to - from == 1) {
178  return building_blocks[from % NUMBER_OF_BUILDING_BLOCKS];
179  }
180  if (to - from == 2) {
181  return FACTORY->NewConsString(
182  building_blocks[from % NUMBER_OF_BUILDING_BLOCKS],
183  building_blocks[(from+1) % NUMBER_OF_BUILDING_BLOCKS]);
184  }
185  Handle<String> part1 =
186  ConstructBalancedHelper(building_blocks, from, from + ((to - from) / 2));
187  Handle<String> part2 =
188  ConstructBalancedHelper(building_blocks, from + ((to - from) / 2), to);
189  return FACTORY->NewConsString(part1, part2);
190 }
191 
192 
193 static Handle<String> ConstructBalanced(
194  Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) {
195  return ConstructBalancedHelper(building_blocks, 0, DEEP_DEPTH);
196 }
197 
198 
199 static StringInputBuffer buffer;
200 
201 
202 static void Traverse(Handle<String> s1, Handle<String> s2) {
203  int i = 0;
204  buffer.Reset(*s1);
205  StringInputBuffer buffer2(*s2);
206  while (buffer.has_more()) {
207  CHECK(buffer2.has_more());
208  uint16_t c = buffer.GetNext();
209  CHECK_EQ(c, buffer2.GetNext());
210  i++;
211  }
212  CHECK_EQ(s1->length(), i);
213  CHECK_EQ(s2->length(), i);
214 }
215 
216 
217 static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) {
218  int i = 0;
219  buffer.Reset(*s1);
220  StringInputBuffer buffer2(*s2);
221  while (buffer.has_more() && i < chars) {
222  CHECK(buffer2.has_more());
223  uint16_t c = buffer.GetNext();
224  CHECK_EQ(c, buffer2.GetNext());
225  i++;
226  }
227  s1->Get(s1->length() - 1);
228  s2->Get(s2->length() - 1);
229 }
230 
231 
232 TEST(Traverse) {
233  printf("TestTraverse\n");
234  InitializeVM();
235  v8::HandleScope scope;
236  Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS];
237  ZoneScope zone(Isolate::Current(), DELETE_ON_EXIT);
238  InitializeBuildingBlocks(building_blocks);
239  Handle<String> flat = ConstructBalanced(building_blocks);
240  FlattenString(flat);
241  Handle<String> left_asymmetric = ConstructLeft(building_blocks, DEEP_DEPTH);
242  Handle<String> right_asymmetric = ConstructRight(building_blocks, DEEP_DEPTH);
243  Handle<String> symmetric = ConstructBalanced(building_blocks);
244  printf("1\n");
245  Traverse(flat, symmetric);
246  printf("2\n");
247  Traverse(flat, left_asymmetric);
248  printf("3\n");
249  Traverse(flat, right_asymmetric);
250  printf("4\n");
251  Handle<String> left_deep_asymmetric =
252  ConstructLeft(building_blocks, SUPER_DEEP_DEPTH);
253  Handle<String> right_deep_asymmetric =
254  ConstructRight(building_blocks, SUPER_DEEP_DEPTH);
255  printf("5\n");
256  TraverseFirst(left_asymmetric, left_deep_asymmetric, 1050);
257  printf("6\n");
258  TraverseFirst(left_asymmetric, right_deep_asymmetric, 65536);
259  printf("7\n");
260  FlattenString(left_asymmetric);
261  printf("10\n");
262  Traverse(flat, left_asymmetric);
263  printf("11\n");
264  FlattenString(right_asymmetric);
265  printf("12\n");
266  Traverse(flat, right_asymmetric);
267  printf("14\n");
268  FlattenString(symmetric);
269  printf("15\n");
270  Traverse(flat, symmetric);
271  printf("16\n");
272  FlattenString(left_deep_asymmetric);
273  printf("18\n");
274 }
275 
276 
277 static const int DEEP_ASCII_DEPTH = 100000;
278 
279 
280 TEST(DeepAscii) {
281  printf("TestDeepAscii\n");
282  InitializeVM();
283  v8::HandleScope scope;
284 
285  char* foo = NewArray<char>(DEEP_ASCII_DEPTH);
286  for (int i = 0; i < DEEP_ASCII_DEPTH; i++) {
287  foo[i] = "foo "[i % 4];
288  }
289  Handle<String> string =
290  FACTORY->NewStringFromAscii(Vector<const char>(foo, DEEP_ASCII_DEPTH));
291  Handle<String> foo_string = FACTORY->NewStringFromAscii(CStrVector("foo"));
292  for (int i = 0; i < DEEP_ASCII_DEPTH; i += 10) {
293  string = FACTORY->NewConsString(string, foo_string);
294  }
295  Handle<String> flat_string = FACTORY->NewConsString(string, foo_string);
296  FlattenString(flat_string);
297 
298  for (int i = 0; i < 500; i++) {
299  TraverseFirst(flat_string, string, DEEP_ASCII_DEPTH);
300  }
301  DeleteArray<char>(foo);
302 }
303 
304 
305 TEST(Utf8Conversion) {
306  // Smoke test for converting strings to utf-8.
307  InitializeVM();
308  v8::HandleScope handle_scope;
309  // A simple ascii string
310  const char* ascii_string = "abcdef12345";
311  int len =
312  v8::String::New(ascii_string,
313  StrLength(ascii_string))->Utf8Length();
314  CHECK_EQ(StrLength(ascii_string), len);
315  // A mixed ascii and non-ascii string
316  // U+02E4 -> CB A4
317  // U+0064 -> 64
318  // U+12E4 -> E1 8B A4
319  // U+0030 -> 30
320  // U+3045 -> E3 81 85
321  const uint16_t mixed_string[] = {0x02E4, 0x0064, 0x12E4, 0x0030, 0x3045};
322  // The characters we expect to be output
323  const unsigned char as_utf8[11] = {0xCB, 0xA4, 0x64, 0xE1, 0x8B, 0xA4, 0x30,
324  0xE3, 0x81, 0x85, 0x00};
325  // The number of bytes expected to be written for each length
326  const int lengths[12] = {0, 0, 2, 3, 3, 3, 6, 7, 7, 7, 10, 11};
327  const int char_lengths[12] = {0, 0, 1, 2, 2, 2, 3, 4, 4, 4, 5, 5};
328  v8::Handle<v8::String> mixed = v8::String::New(mixed_string, 5);
329  CHECK_EQ(10, mixed->Utf8Length());
330  // Try encoding the string with all capacities
331  char buffer[11];
332  const char kNoChar = static_cast<char>(-1);
333  for (int i = 0; i <= 11; i++) {
334  // Clear the buffer before reusing it
335  for (int j = 0; j < 11; j++)
336  buffer[j] = kNoChar;
337  int chars_written;
338  int written = mixed->WriteUtf8(buffer, i, &chars_written);
339  CHECK_EQ(lengths[i], written);
340  CHECK_EQ(char_lengths[i], chars_written);
341  // Check that the contents are correct
342  for (int j = 0; j < lengths[i]; j++)
343  CHECK_EQ(as_utf8[j], static_cast<unsigned char>(buffer[j]));
344  // Check that the rest of the buffer hasn't been touched
345  for (int j = lengths[i]; j < 11; j++)
346  CHECK_EQ(kNoChar, buffer[j]);
347  }
348 }
349 
350 
351 TEST(ExternalShortStringAdd) {
352  ZoneScope zonescope(Isolate::Current(), DELETE_ON_EXIT);
353 
354  InitializeVM();
355  v8::HandleScope handle_scope;
356  Zone* zone = Isolate::Current()->zone();
357 
358  // Make sure we cover all always-flat lengths and at least one above.
359  static const int kMaxLength = 20;
360  CHECK_GT(kMaxLength, i::ConsString::kMinLength);
361 
362  // Allocate two JavaScript arrays for holding short strings.
363  v8::Handle<v8::Array> ascii_external_strings =
364  v8::Array::New(kMaxLength + 1);
365  v8::Handle<v8::Array> non_ascii_external_strings =
366  v8::Array::New(kMaxLength + 1);
367 
368  // Generate short ascii and non-ascii external strings.
369  for (int i = 0; i <= kMaxLength; i++) {
370  char* ascii = zone->NewArray<char>(i + 1);
371  for (int j = 0; j < i; j++) {
372  ascii[j] = 'a';
373  }
374  // Terminating '\0' is left out on purpose. It is not required for external
375  // string data.
376  AsciiResource* ascii_resource =
377  new(zone) AsciiResource(Vector<const char>(ascii, i));
378  v8::Local<v8::String> ascii_external_string =
379  v8::String::NewExternal(ascii_resource);
380 
381  ascii_external_strings->Set(v8::Integer::New(i), ascii_external_string);
382  uc16* non_ascii = zone->NewArray<uc16>(i + 1);
383  for (int j = 0; j < i; j++) {
384  non_ascii[j] = 0x1234;
385  }
386  // Terminating '\0' is left out on purpose. It is not required for external
387  // string data.
388  Resource* resource = new(zone) Resource(Vector<const uc16>(non_ascii, i));
389  v8::Local<v8::String> non_ascii_external_string =
390  v8::String::NewExternal(resource);
391  non_ascii_external_strings->Set(v8::Integer::New(i),
392  non_ascii_external_string);
393  }
394 
395  // Add the arrays with the short external strings in the global object.
396  v8::Handle<v8::Object> global = env->Global();
397  global->Set(v8_str("external_ascii"), ascii_external_strings);
398  global->Set(v8_str("external_non_ascii"), non_ascii_external_strings);
399  global->Set(v8_str("max_length"), v8::Integer::New(kMaxLength));
400 
401  // Add short external ascii and non-ascii strings checking the result.
402  static const char* source =
403  "function test() {"
404  " var ascii_chars = 'aaaaaaaaaaaaaaaaaaaa';"
405  " var non_ascii_chars = '\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234\\u1234';" //NOLINT
406  " if (ascii_chars.length != max_length) return 1;"
407  " if (non_ascii_chars.length != max_length) return 2;"
408  " var ascii = Array(max_length + 1);"
409  " var non_ascii = Array(max_length + 1);"
410  " for (var i = 0; i <= max_length; i++) {"
411  " ascii[i] = ascii_chars.substring(0, i);"
412  " non_ascii[i] = non_ascii_chars.substring(0, i);"
413  " };"
414  " for (var i = 0; i <= max_length; i++) {"
415  " if (ascii[i] != external_ascii[i]) return 3;"
416  " if (non_ascii[i] != external_non_ascii[i]) return 4;"
417  " for (var j = 0; j < i; j++) {"
418  " if (external_ascii[i] !="
419  " (external_ascii[j] + external_ascii[i - j])) return 5;"
420  " if (external_non_ascii[i] !="
421  " (external_non_ascii[j] + external_non_ascii[i - j])) return 6;"
422  " if (non_ascii[i] != (non_ascii[j] + non_ascii[i - j])) return 7;"
423  " if (ascii[i] != (ascii[j] + ascii[i - j])) return 8;"
424  " if (ascii[i] != (external_ascii[j] + ascii[i - j])) return 9;"
425  " if (ascii[i] != (ascii[j] + external_ascii[i - j])) return 10;"
426  " if (non_ascii[i] !="
427  " (external_non_ascii[j] + non_ascii[i - j])) return 11;"
428  " if (non_ascii[i] !="
429  " (non_ascii[j] + external_non_ascii[i - j])) return 12;"
430  " }"
431  " }"
432  " return 0;"
433  "};"
434  "test()";
435  CHECK_EQ(0, CompileRun(source)->Int32Value());
436 }
437 
438 
439 TEST(CachedHashOverflow) {
440  // We incorrectly allowed strings to be tagged as array indices even if their
441  // values didn't fit in the hash field.
442  // See http://code.google.com/p/v8/issues/detail?id=728
443  ZoneScope zone(Isolate::Current(), DELETE_ON_EXIT);
444 
445  InitializeVM();
446  v8::HandleScope handle_scope;
447  // Lines must be executed sequentially. Combining them into one script
448  // makes the bug go away.
449  const char* lines[] = {
450  "var x = [];",
451  "x[4] = 42;",
452  "var s = \"1073741828\";",
453  "x[s];",
454  "x[s] = 37;",
455  "x[4];",
456  "x[s];",
457  NULL
458  };
459 
460  Handle<Smi> fortytwo(Smi::FromInt(42));
461  Handle<Smi> thirtyseven(Smi::FromInt(37));
462  Handle<Object> results[] = {
463  FACTORY->undefined_value(),
464  fortytwo,
465  FACTORY->undefined_value(),
466  FACTORY->undefined_value(),
467  thirtyseven,
468  fortytwo,
469  thirtyseven // Bug yielded 42 here.
470  };
471 
472  const char* line;
473  for (int i = 0; (line = lines[i]); i++) {
474  printf("%s\n", line);
475  v8::Local<v8::Value> result =
476  v8::Script::Compile(v8::String::New(line))->Run();
477  CHECK_EQ(results[i]->IsUndefined(), result->IsUndefined());
478  CHECK_EQ(results[i]->IsNumber(), result->IsNumber());
479  if (result->IsNumber()) {
480  CHECK_EQ(Smi::cast(results[i]->ToSmi()->ToObjectChecked())->value(),
481  result->ToInt32()->Value());
482  }
483  }
484 }
485 
486 
487 TEST(SliceFromCons) {
488  FLAG_string_slices = true;
489  InitializeVM();
490  v8::HandleScope scope;
491  Handle<String> string =
492  FACTORY->NewStringFromAscii(CStrVector("parentparentparent"));
493  Handle<String> parent = FACTORY->NewConsString(string, string);
494  CHECK(parent->IsConsString());
495  CHECK(!parent->IsFlat());
496  Handle<String> slice = FACTORY->NewSubString(parent, 1, 25);
497  // After slicing, the original string becomes a flat cons.
498  CHECK(parent->IsFlat());
499  CHECK(slice->IsSlicedString());
501  ConsString::cast(*parent)->first());
502  CHECK(SlicedString::cast(*slice)->parent()->IsSeqString());
503  CHECK(slice->IsFlat());
504 }
505 
506 
508  public:
510  : data_(vector) {}
511  virtual ~AsciiVectorResource() {}
512  virtual size_t length() const { return data_.length(); }
513  virtual const char* data() const { return data_.start(); }
514  private:
515  i::Vector<const char> data_;
516 };
517 
518 
519 TEST(SliceFromExternal) {
520  FLAG_string_slices = true;
521  InitializeVM();
522  v8::HandleScope scope;
523  AsciiVectorResource resource(
524  i::Vector<const char>("abcdefghijklmnopqrstuvwxyz", 26));
525  Handle<String> string = FACTORY->NewExternalStringFromAscii(&resource);
526  CHECK(string->IsExternalString());
527  Handle<String> slice = FACTORY->NewSubString(string, 1, 25);
528  CHECK(slice->IsSlicedString());
529  CHECK(string->IsExternalString());
530  CHECK_EQ(SlicedString::cast(*slice)->parent(), *string);
531  CHECK(SlicedString::cast(*slice)->parent()->IsExternalString());
532  CHECK(slice->IsFlat());
533 }
534 
535 
536 TEST(TrivialSlice) {
537  // This tests whether a slice that contains the entire parent string
538  // actually creates a new string (it should not).
539  FLAG_string_slices = true;
540  InitializeVM();
541  HandleScope scope;
542  v8::Local<v8::Value> result;
543  Handle<String> string;
544  const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';";
545  const char* check = "str.slice(0,26)";
546  const char* crosscheck = "str.slice(1,25)";
547 
548  CompileRun(init);
549 
550  result = CompileRun(check);
551  CHECK(result->IsString());
552  string = v8::Utils::OpenHandle(v8::String::Cast(*result));
553  CHECK(!string->IsSlicedString());
554 
555  string = FACTORY->NewSubString(string, 0, 26);
556  CHECK(!string->IsSlicedString());
557  result = CompileRun(crosscheck);
558  CHECK(result->IsString());
559  string = v8::Utils::OpenHandle(v8::String::Cast(*result));
560  CHECK(string->IsSlicedString());
561  CHECK_EQ("bcdefghijklmnopqrstuvwxy", *(string->ToCString()));
562 }
563 
564 
565 TEST(SliceFromSlice) {
566  // This tests whether a slice that contains the entire parent string
567  // actually creates a new string (it should not).
568  FLAG_string_slices = true;
569  InitializeVM();
570  HandleScope scope;
571  v8::Local<v8::Value> result;
572  Handle<String> string;
573  const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';";
574  const char* slice = "var slice = str.slice(1,-1); slice";
575  const char* slice_from_slice = "slice.slice(1,-1);";
576 
577  CompileRun(init);
578  result = CompileRun(slice);
579  CHECK(result->IsString());
580  string = v8::Utils::OpenHandle(v8::String::Cast(*result));
581  CHECK(string->IsSlicedString());
582  CHECK(SlicedString::cast(*string)->parent()->IsSeqString());
583  CHECK_EQ("bcdefghijklmnopqrstuvwxy", *(string->ToCString()));
584 
585  result = CompileRun(slice_from_slice);
586  CHECK(result->IsString());
587  string = v8::Utils::OpenHandle(v8::String::Cast(*result));
588  CHECK(string->IsSlicedString());
589  CHECK(SlicedString::cast(*string)->parent()->IsSeqString());
590  CHECK_EQ("cdefghijklmnopqrstuvwx", *(string->ToCString()));
591 }
592 
593 
594 TEST(AsciiArrayJoin) {
595  // Set heap limits.
596  static const int K = 1024;
597  v8::ResourceConstraints constraints;
598  constraints.set_max_young_space_size(256 * K);
599  constraints.set_max_old_space_size(4 * K * K);
600  v8::SetResourceConstraints(&constraints);
601 
602  // String s is made of 2^17 = 131072 'c' characters and a is an array
603  // starting with 'bad', followed by 2^14 times the string s. That means the
604  // total length of the concatenated strings is 2^31 + 3. So on 32bit systems
605  // summing the lengths of the strings (as Smis) overflows and wraps.
606  static const char* join_causing_out_of_memory =
607  "var two_14 = Math.pow(2, 14);"
608  "var two_17 = Math.pow(2, 17);"
609  "var s = Array(two_17 + 1).join('c');"
610  "var a = ['bad'];"
611  "for (var i = 1; i <= two_14; i++) a.push(s);"
612  "a.join("");";
613 
614  v8::HandleScope scope;
615  LocalContext context;
617  v8::Local<v8::Script> script =
618  v8::Script::Compile(v8::String::New(join_causing_out_of_memory));
619  v8::Local<v8::Value> result = script->Run();
620 
621  // Check for out of memory state.
622  CHECK(result.IsEmpty());
623  CHECK(context->HasOutOfMemoryException());
624 }
625 
626 
627 static void CheckException(const char* source) {
628  // An empty handle is returned upon exception.
629  CHECK(CompileRun(source).IsEmpty());
630 }
631 
632 
633 TEST(RobustSubStringStub) {
634  // This tests whether the SubStringStub can handle unsafe arguments.
635  // If not recognized, those unsafe arguments lead to out-of-bounds reads.
636  FLAG_allow_natives_syntax = true;
637  InitializeVM();
638  HandleScope scope;
639  v8::Local<v8::Value> result;
640  Handle<String> string;
641  CompileRun("var short = 'abcdef';");
642 
643  // Invalid indices.
644  CheckException("%_SubString(short, 0, 10000);");
645  CheckException("%_SubString(short, -1234, 5);");
646  CheckException("%_SubString(short, 5, 2);");
647  // Special HeapNumbers.
648  CheckException("%_SubString(short, 1, Infinity);");
649  CheckException("%_SubString(short, NaN, 5);");
650  // String arguments.
651  CheckException("%_SubString(short, '2', '5');");
652  // Ordinary HeapNumbers can be handled (in runtime).
653  result = CompileRun("%_SubString(short, Math.sqrt(4), 5.1);");
654  string = v8::Utils::OpenHandle(v8::String::Cast(*result));
655  CHECK_EQ("cde", *(string->ToCString()));
656 
657  CompileRun("var long = 'abcdefghijklmnopqrstuvwxyz';");
658  // Invalid indices.
659  CheckException("%_SubString(long, 0, 10000);");
660  CheckException("%_SubString(long, -1234, 17);");
661  CheckException("%_SubString(long, 17, 2);");
662  // Special HeapNumbers.
663  CheckException("%_SubString(long, 1, Infinity);");
664  CheckException("%_SubString(long, NaN, 17);");
665  // String arguments.
666  CheckException("%_SubString(long, '2', '17');");
667  // Ordinary HeapNumbers within bounds can be handled (in runtime).
668  result = CompileRun("%_SubString(long, Math.sqrt(4), 17.1);");
669  string = v8::Utils::OpenHandle(v8::String::Cast(*result));
670  CHECK_EQ("cdefghijklmnopq", *(string->ToCString()));
671 
672  // Test that out-of-bounds substring of a slice fails when the indices
673  // would have been valid for the underlying string.
674  CompileRun("var slice = long.slice(1, 15);");
675  CheckException("%_SubString(slice, 0, 17);");
676 }
677 
678 
679 TEST(RegExpOverflow) {
680  // Result string has the length 2^32, causing a 32-bit integer overflow.
681  InitializeVM();
682  HandleScope scope;
683  LocalContext context;
685  v8::Local<v8::Value> result = CompileRun(
686  "var a = 'a'; "
687  "for (var i = 0; i < 16; i++) { "
688  " a += a; "
689  "} "
690  "a.replace(/a/g, a); ");
691  CHECK(result.IsEmpty());
692  CHECK(context->HasOutOfMemoryException());
693 }
const SwVfpRegister s2
static Local< Script > Compile(Handle< String > source, ScriptOrigin *origin=NULL, ScriptData *pre_data=NULL, Handle< String > script_data=Handle< String >())
Definition: api.cc:1560
void FlattenString(Handle< String > string)
Definition: handles.cc:211
V8EXPORT int WriteUtf8(char *buffer, int length=-1, int *nchars_ref=NULL, int options=NO_OPTIONS) const
Definition: api.cc:3829
void set_max_young_space_size(int value)
Definition: v8.h:2608
#define CHECK_EQ(expected, value)
Definition: checks.h:219
bool HasOutOfMemoryException()
Definition: api.cc:4418
static Smi * FromInt(int value)
Definition: objects-inl.h:973
#define CHECK_GT(a, b)
Definition: checks.h:227
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4655
V8EXPORT Local< Int32 > ToInt32() const
Definition: api.cc:2589
unsigned short uint16_t
Definition: unicode.cc:46
#define CHECK(condition)
Definition: checks.h:56
AsciiResource(Vector< const char > string)
Definition: test-strings.cc:69
virtual const char * data() const
static Smi * cast(Object *object)
unsigned int seed
Definition: test-strings.cc:17
int foo
virtual size_t length() const
Definition: test-strings.cc:58
static const int kMinLength
Definition: objects.h:7433
void set_max_old_space_size(int value)
Definition: v8.h:2610
static SlicedString * cast(Object *obj)
V8EXPORT int Utf8Length() const
Definition: api.cc:3725
virtual ~AsciiVectorResource()
virtual size_t length() const
Definition: test-strings.cc:73
static String * Cast(v8::Value *obj)
Definition: v8.h:4242
virtual const uint16_t * data() const
Definition: test-strings.cc:57
Definition: v8.h:104
virtual const char * data() const
Definition: test-strings.cc:72
bool IsUndefined() const
Definition: v8.h:4277
T * NewArray(int length)
Definition: zone-inl.h:72
Vector< const char > CStrVector(const char *data)
Definition: utils.h:525
int StrLength(const char *string)
Definition: utils.h:234
bool IsString() const
Definition: v8.h:4313
const SwVfpRegister s1
V8EXPORT bool IsNumber() const
Definition: api.cc:2175
uint16_t uc16
Definition: globals.h:273
AsciiVectorResource(i::Vector< const char > vector)
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
Definition: flags.cc:274
static V8EXPORT Local< Integer > New(int32_t value)
Definition: api.cc:5100
virtual size_t length() const
bool IsEmpty() const
Definition: v8.h:208
Local< Value > Run()
Definition: api.cc:1590
#define FACTORY
Definition: isolate.h:1409
void Reset(Input input)
Definition: unicode-inl.h:231
static Persistent< Context > New(ExtensionConfiguration *extensions=NULL, Handle< ObjectTemplate > global_template=Handle< ObjectTemplate >(), Handle< Value > global_object=Handle< Value >())
Definition: api.cc:4308
static V8EXPORT Local< String > NewExternal(ExternalStringResource *resource)
Definition: api.cc:4747
bool V8EXPORT SetResourceConstraints(ResourceConstraints *constraints)
Definition: api.cc:593
static ConsString * cast(Object *obj)
void check(i::Vector< const char > string)
Definition: v8.h:105
Resource(Vector< const uc16 > string)
Definition: test-strings.cc:54
static V8EXPORT Local< Object > New()
Definition: api.cc:4829
static v8::internal::Handle< v8::internal::TemplateInfo > OpenHandle(const Template *that)
V8EXPORT bool Set(Handle< Value > key, Handle< Value > value, PropertyAttribute attribs=None)
Definition: api.cc:2757
static void IgnoreOutOfMemoryException()
Definition: api.cc:5125