Revision: 20202
Author:   [email protected]
Date:     Mon Mar 24 15:01:17 2014 UTC
Log:      No longer OOM on invalid string length.

[email protected]
BUG=v8:3060
LOG=Y

Review URL: https://codereview.chromium.org/207613005
http://code.google.com/p/v8/source/detail?r=20202

Modified:
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/bootstrapper.cc
 /branches/bleeding_edge/src/bootstrapper.h
 /branches/bleeding_edge/src/contexts.cc
 /branches/bleeding_edge/src/debug.cc
 /branches/bleeding_edge/src/factory.cc
 /branches/bleeding_edge/src/heap-inl.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/hydrogen-instructions.cc
 /branches/bleeding_edge/src/json-parser.h
 /branches/bleeding_edge/src/json-stringifier.h
 /branches/bleeding_edge/src/jsregexp.cc
 /branches/bleeding_edge/src/liveedit.cc
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/uri.h
 /branches/bleeding_edge/test/cctest/cctest.status
 /branches/bleeding_edge/test/cctest/test-strings.cc
/branches/bleeding_edge/test/mjsunit/string-oom-replace-global-regexp-with-string.js
 /branches/bleeding_edge/tools/lexer-shell.cc

=======================================
--- /branches/bleeding_edge/src/api.cc  Mon Mar 24 12:13:58 2014 UTC
+++ /branches/bleeding_edge/src/api.cc  Mon Mar 24 15:01:17 2014 UTC
@@ -5403,6 +5403,8 @@
   if (length == -1) length = StringLength(data);
   i::Handle<i::String> result = NewString(
       isolate->factory(), type, i::Vector<const Char>(data, length));
+  // We do not expect this to fail. Change this if it does.
+  CHECK(!result.is_null());
   if (type == String::kUndetectableString) {
     result->MarkAsUndetectable();
   }
@@ -5460,8 +5462,8 @@
   i::Handle<i::String> right_string = Utils::OpenHandle(*right);
i::Handle<i::String> result = isolate->factory()->NewConsString(left_string, right_string);
-  // We do not expect this to throw an exception. Change this if it does.
-  CHECK_NOT_EMPTY_HANDLE(isolate, result);
+  // We do not expect this to fail. Change this if it does.
+  CHECK(!result.is_null());
   return Utils::ToLocal(result);
 }

@@ -5469,14 +5471,22 @@
 static i::Handle<i::String> NewExternalStringHandle(
     i::Isolate* isolate,
     v8::String::ExternalStringResource* resource) {
-  return isolate->factory()->NewExternalStringFromTwoByte(resource);
+  i::Handle<i::String> result =
+      isolate->factory()->NewExternalStringFromTwoByte(resource);
+  // We do not expect this to fail. Change this if it does.
+  CHECK(!result.is_null());
+  return result;
 }


 static i::Handle<i::String> NewExternalAsciiStringHandle(
     i::Isolate* isolate,
     v8::String::ExternalAsciiStringResource* resource) {
-  return isolate->factory()->NewExternalStringFromAscii(resource);
+  i::Handle<i::String> result =
+      isolate->factory()->NewExternalStringFromAscii(resource);
+  // We do not expect this to fail. Change this if it does.
+  CHECK(!result.is_null());
+  return result;
 }


@@ -6130,6 +6140,8 @@
     if (length == -1) length = i::StrLength(data);
     i::Handle<i::String> name = i_isolate->factory()->NewStringFromUtf8(
         i::Vector<const char>(data, length));
+    // We do not expect this to fail. Change this if it does.
+    CHECK(!name.is_null());
     result->set_name(*name);
   }
   return Utils::ToLocal(result);
@@ -6951,8 +6963,8 @@
     i::Handle<i::String> cons = isolate->factory()->NewConsString(
         isolate->factory()->InternalizeUtf8String(entry->name_prefix()),
         isolate->factory()->InternalizeUtf8String(entry->name()));
-    // We do not expect this to throw an exception. Change this if it does.
-    CHECK_NOT_EMPTY_HANDLE(isolate, cons);
+    // We do not expect this to fail. Change this if it does.
+    CHECK(!cons.is_null());
     return ToApiHandle<String>(cons);
   }
 }
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Mon Mar 24 10:07:15 2014 UTC
+++ /branches/bleeding_edge/src/bootstrapper.cc Mon Mar 24 15:01:17 2014 UTC
@@ -88,6 +88,8 @@
                                           source.length());
     Handle<String> source_code =
         isolate_->factory()->NewExternalStringFromAscii(resource);
+    // We do not expect this to throw an exception. Change this if it does.
+    CHECK_NOT_EMPTY_HANDLE(isolate_, source_code);
     heap->natives_source_cache()->set(index, *source_code);
   }
   Handle<Object> cached_source(heap->natives_source_cache()->get(index),
@@ -1463,6 +1465,7 @@
   Handle<String> source_code =
       factory->NewStringFromAscii(
           ExperimentalNatives::GetRawScriptSource(index));
+  RETURN_IF_EMPTY_HANDLE_VALUE(isolate, source_code, false);
   return CompileNative(isolate, name, source_code);
 }

@@ -1512,6 +1515,7 @@
   if (cache == NULL || !cache->Lookup(name, &function_info)) {
     ASSERT(source->IsOneByteRepresentation());
     Handle<String> script_name = factory->NewStringFromUtf8(name);
+    ASSERT(!script_name.is_null());
     function_info = Compiler::CompileScript(
         source,
         script_name,
@@ -2080,8 +2084,10 @@
   ASSERT_EQ(".prototype", period_pos);
   Vector<const char> property(holder_expr,
                               static_cast<int>(period_pos - holder_expr));
+ Handle<String> property_string = factory->InternalizeUtf8String(property);
+  ASSERT(!property_string.is_null());
   Handle<JSFunction> function = Handle<JSFunction>::cast(
- GetProperty(isolate, global, factory->InternalizeUtf8String(property)));
+      GetProperty(isolate, global, property_string));
   return Handle<JSObject>(JSObject::cast(function->prototype()));
 }

@@ -2349,6 +2355,8 @@
   }
   Handle<String> source_code =
       isolate->factory()->NewExternalStringFromAscii(extension->source());
+  // We do not expect this to throw an exception. Change this if it does.
+  CHECK_NOT_EMPTY_HANDLE(isolate, source_code);
   bool result = CompileScriptCached(isolate,
                                     CStrVector(extension->name()),
                                     source_code,
=======================================
--- /branches/bleeding_edge/src/bootstrapper.h  Fri Jan 17 10:52:00 2014 UTC
+++ /branches/bleeding_edge/src/bootstrapper.h  Mon Mar 24 15:01:17 2014 UTC
@@ -73,6 +73,7 @@
     cache_->CopyTo(0, *new_array, 0, cache_->length());
     cache_ = *new_array;
     Handle<String> str = factory->NewStringFromAscii(name, TENURED);
+    ASSERT(!str.is_null());
     cache_->set(length, *str);
     cache_->set(length + 1, *shared);
     Script::cast(shared->script())->set_type(Smi::FromInt(type_));
=======================================
--- /branches/bleeding_edge/src/contexts.cc     Thu Mar 13 11:55:31 2014 UTC
+++ /branches/bleeding_edge/src/contexts.cc     Mon Mar 24 15:01:17 2014 UTC
@@ -368,7 +368,7 @@
   Handle<Object> result(error_message_for_code_gen_from_strings(),
                         GetIsolate());
   if (!result->IsUndefined()) return result;
-  return GetIsolate()->factory()->NewStringFromAscii(i::CStrVector(
+  return GetIsolate()->factory()->NewStringFromOneByte(STATIC_ASCII_VECTOR(
       "Code generation from strings disallowed for this context"));
 }

=======================================
--- /branches/bleeding_edge/src/debug.cc        Wed Mar 19 13:24:13 2014 UTC
+++ /branches/bleeding_edge/src/debug.cc        Mon Mar 24 15:01:17 2014 UTC
@@ -754,6 +754,7 @@
       isolate->bootstrapper()->NativesSourceLookup(index);
   Vector<const char> name = Natives::GetScriptName(index);
   Handle<String> script_name = factory->NewStringFromAscii(name);
+  ASSERT(!script_name.is_null());
   Handle<Context> context = isolate->native_context();

   // Compile the script.
@@ -2599,6 +2600,7 @@
   // Create the execution state object.
   Handle<String> constructor_str =
       isolate_->factory()->InternalizeUtf8String(constructor_name);
+  ASSERT(!constructor_str.is_null());
   Handle<Object> constructor(
isolate_->global_object()->GetPropertyNoExceptionThrown(*constructor_str),
       isolate_);
=======================================
--- /branches/bleeding_edge/src/factory.cc      Fri Mar 21 11:22:16 2014 UTC
+++ /branches/bleeding_edge/src/factory.cc      Mon Mar 24 15:01:17 2014 UTC
@@ -289,7 +289,7 @@


 Handle<SeqOneByteString> Factory::NewRawOneByteString(int length,
- PretenureFlag pretenure) { + PretenureFlag pretenure) {
   CALL_HEAP_FUNCTION(
       isolate(),
       isolate()->heap()->AllocateRawOneByteString(length, pretenure),
@@ -411,6 +411,7 @@
     ASSERT(left->IsFlat());
     ASSERT(right->IsFlat());

+    STATIC_ASSERT(ConsString::kMinLength <= String::kMaxLength);
     if (is_one_byte) {
       Handle<SeqOneByteString> result = NewRawOneByteString(length);
       DisallowHeapAllocation no_gc;
@@ -496,12 +497,14 @@
   if (!FLAG_string_slices || length < SlicedString::kMinLength) {
     if (str->IsOneByteRepresentation()) {
       Handle<SeqOneByteString> result = NewRawOneByteString(length);
+      ASSERT(!result.is_null());
       uint8_t* dest = result->GetChars();
       DisallowHeapAllocation no_gc;
       String::WriteToFlat(*str, dest, begin, end);
       return result;
     } else {
       Handle<SeqTwoByteString> result = NewRawTwoByteString(length);
+      ASSERT(!result.is_null());
       uc16* dest = result->GetChars();
       DisallowHeapAllocation no_gc;
       String::WriteToFlat(*str, dest, begin, end);
=======================================
--- /branches/bleeding_edge/src/heap-inl.h      Mon Mar 24 10:07:15 2014 UTC
+++ /branches/bleeding_edge/src/heap-inl.h      Mon Mar 24 15:01:17 2014 UTC
@@ -138,7 +138,7 @@
MaybeObject* Heap::AllocateOneByteInternalizedString(Vector<const uint8_t> str,
                                                      uint32_t hash_field) {
   if (str.length() > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return isolate()->ThrowInvalidStringLength();
   }
   // Compute map and object size.
   Map* map = ascii_internalized_string_map();
@@ -171,7 +171,7 @@
MaybeObject* Heap::AllocateTwoByteInternalizedString(Vector<const uc16> str,
                                                      uint32_t hash_field) {
   if (str.length() > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return isolate()->ThrowInvalidStringLength();
   }
   // Compute map and object size.
   Map* map = internalized_string_map();
=======================================
--- /branches/bleeding_edge/src/heap.cc Mon Mar 24 10:07:15 2014 UTC
+++ /branches/bleeding_edge/src/heap.cc Mon Mar 24 15:01:17 2014 UTC
@@ -3871,7 +3871,7 @@
     const ExternalAsciiString::Resource* resource) {
   size_t length = resource->length();
   if (length > static_cast<size_t>(String::kMaxLength)) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return isolate()->ThrowInvalidStringLength();
   }

   Map* map = external_ascii_string_map();
@@ -3893,7 +3893,7 @@
     const ExternalTwoByteString::Resource* resource) {
   size_t length = resource->length();
   if (length > static_cast<size_t>(String::kMaxLength)) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return isolate()->ThrowInvalidStringLength();
   }

   // For small strings we check whether the resource contains only
@@ -4978,8 +4978,8 @@
   int size;
   Map* map;

-  if (chars > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+  if (chars < 0 || chars > String::kMaxLength) {
+    return isolate()->ThrowInvalidStringLength();
   }
   if (is_one_byte) {
     map = ascii_internalized_string_map();
@@ -5027,7 +5027,7 @@
 MaybeObject* Heap::AllocateRawOneByteString(int length,
                                             PretenureFlag pretenure) {
   if (length < 0 || length > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return isolate()->ThrowInvalidStringLength();
   }
   int size = SeqOneByteString::SizeFor(length);
   ASSERT(size <= SeqOneByteString::kMaxSize);
@@ -5051,7 +5051,7 @@
 MaybeObject* Heap::AllocateRawTwoByteString(int length,
                                             PretenureFlag pretenure) {
   if (length < 0 || length > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return isolate()->ThrowInvalidStringLength();
   }
   int size = SeqTwoByteString::SizeFor(length);
   ASSERT(size <= SeqTwoByteString::kMaxSize);
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Fri Mar 21 09:28:26 2014 UTC +++ /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Mar 24 15:01:17 2014 UTC
@@ -3923,9 +3923,15 @@
     HConstant* c_right = HConstant::cast(right);
     HConstant* c_left = HConstant::cast(left);
     if (c_left->HasStringValue() && c_right->HasStringValue()) {
- Handle<String> concat = zone->isolate()->factory()->NewFlatConcatString(
-          c_left->StringValue(), c_right->StringValue());
-      return HConstant::New(zone, context, concat);
+      Handle<String> left_string = c_left->StringValue();
+      Handle<String> right_string = c_right->StringValue();
+      // Prevent possible exception by invalid string length.
+ if (left_string->length() + right_string->length() < String::kMaxLength) { + Handle<String> concat = zone->isolate()->factory()->NewFlatConcatString(
+            c_left->StringValue(), c_right->StringValue());
+        ASSERT(!concat.is_null());
+        return HConstant::New(zone, context, concat);
+      }
     }
   }
   return new(zone) HStringAdd(
=======================================
--- /branches/bleeding_edge/src/json-parser.h   Tue Mar 11 14:41:22 2014 UTC
+++ /branches/bleeding_edge/src/json-parser.h   Mon Mar 24 15:01:17 2014 UTC
@@ -606,6 +606,7 @@
int length = Min(max_length, Max(kInitialSpecialStringLength, 2 * count));
   Handle<StringType> seq_string =
       NewRawString<StringType>(factory(), length, pretenure_);
+  ASSERT(!seq_string.is_null());
   // Copy prefix into seq_str.
   SinkChar* dest = seq_string->GetChars();
   String::WriteToFlat(*prefix, dest, start, end);
@@ -793,6 +794,7 @@
   } while (c0_ != '"');
   int length = position_ - beg_pos;
Handle<String> result = factory()->NewRawOneByteString(length, pretenure_);
+  ASSERT(!result.is_null());
   uint8_t* dest = SeqOneByteString::cast(*result)->GetChars();
   String::WriteToFlat(*source_, dest, beg_pos, position_);

=======================================
--- /branches/bleeding_edge/src/json-stringifier.h Thu Mar 20 12:27:36 2014 UTC +++ /branches/bleeding_edge/src/json-stringifier.h Mon Mar 24 15:01:17 2014 UTC
@@ -266,6 +266,7 @@
                            factory_->ToObject(factory_->empty_string()));
   part_length_ = kInitialPartLength;
   current_part_ = factory_->NewRawOneByteString(part_length_);
+  ASSERT(!current_part_.is_null());
   tojson_string_ = factory_->toJSON_string();
   stack_ = factory_->NewJSArray(8);
 }
@@ -309,6 +310,7 @@
   if (object->IsOneByteRepresentationUnderneath()) {
     Handle<String> result =
         isolate->factory()->NewRawOneByteString(worst_case_length);
+    ASSERT(!result.is_null());
     DisallowHeapAllocation no_gc;
     return StringifyString_<SeqOneByteString>(
         isolate,
@@ -317,6 +319,7 @@
   } else {
     Handle<String> result =
         isolate->factory()->NewRawTwoByteString(worst_case_length);
+    ASSERT(!result.is_null());
     DisallowHeapAllocation no_gc;
     return StringifyString_<SeqTwoByteString>(
         isolate,
@@ -722,7 +725,6 @@
 void BasicJsonStringifier::Accumulate() {
if (accumulator()->length() + current_part_->length() > String::kMaxLength) { // Screw it. Simply set the flag and carry on. Throw exception at the end. - // We most likely will trigger a real OOM before even reaching this point.
     set_accumulator(factory_->empty_string());
     overflowed_ = true;
   } else {
@@ -741,6 +743,7 @@
   } else {
     current_part_ = factory_->NewRawTwoByteString(part_length_);
   }
+  ASSERT(!current_part_.is_null());
   current_index_ = 0;
 }

@@ -749,6 +752,7 @@
   ShrinkCurrentPart();
   Accumulate();
   current_part_ = factory_->NewRawTwoByteString(part_length_);
+  ASSERT(!current_part_.is_null());
   current_index_ = 0;
   is_ascii_ = false;
 }
=======================================
--- /branches/bleeding_edge/src/jsregexp.cc     Fri Mar 21 09:28:26 2014 UTC
+++ /branches/bleeding_edge/src/jsregexp.cc     Mon Mar 24 15:01:17 2014 UTC
@@ -466,6 +466,7 @@
     // Unable to compile regexp.
     Handle<String> error_message =
isolate->factory()->NewStringFromUtf8(CStrVector(result.error_message));
+    ASSERT(!error_message.is_null());
     CreateRegExpErrorObjectAndThrow(re, is_ascii, error_message, isolate);
     return false;
   }
=======================================
--- /branches/bleeding_edge/src/liveedit.cc     Thu Mar 20 12:22:13 2014 UTC
+++ /branches/bleeding_edge/src/liveedit.cc     Mon Mar 24 15:01:17 2014 UTC
@@ -2013,8 +2013,8 @@
       DropActivationsInActiveThread(shared_info_array, result, do_drop);
   if (error_message != NULL) {
     // Add error message as an array extra element.
- Vector<const char> vector_message(error_message, StrLength(error_message)); - Handle<String> str = isolate->factory()->NewStringFromAscii(vector_message);
+    Handle<String> str = isolate->factory()->NewStringFromAscii(
+        CStrVector(error_message));
     SetElementSloppy(result, len, str);
   }
   return result;
=======================================
--- /branches/bleeding_edge/src/parser.cc       Mon Mar 24 14:41:55 2014 UTC
+++ /branches/bleeding_edge/src/parser.cc       Mon Mar 24 15:01:17 2014 UTC
@@ -215,6 +215,7 @@
   Handle<String> result = symbol_cache_.at(symbol_id);
   if (result.is_null()) {
     result = scanner()->AllocateInternalizedString(isolate_);
+    ASSERT(!result.is_null());
     symbol_cache_.at(symbol_id) = result;
     return result;
   }
@@ -615,6 +616,7 @@
   Handle<FixedArray> elements = factory->NewFixedArray(args.length());
   for (int i = 0; i < args.length(); i++) {
Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
+    ASSERT(!arg_string.is_null());
     elements->set(i, *arg_string);
   }
   Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
@@ -672,7 +674,10 @@
       parser_->scanner()->LogSymbol(parser_->log_, parser_->position());
     }
   }
-  return parser_->scanner()->AllocateInternalizedString(parser_->isolate_);
+  Handle<String> result =
+      parser_->scanner()->AllocateInternalizedString(parser_->isolate_);
+  ASSERT(!result.is_null());
+  return result;
 }


@@ -1709,8 +1714,8 @@
         return;
       }
       Handle<String> message_string =
-          isolate()->factory()->NewStringFromUtf8(CStrVector("Variable"),
-                                                  TENURED);
+          isolate()->factory()->InternalizeOneByteString(
+              STATIC_ASCII_VECTOR("Variable"));
       Expression* expression =
           NewThrowTypeError(isolate()->factory()->redeclaration_string(),
                             message_string, name);
@@ -3816,6 +3821,7 @@
 RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
   failed_ = true;
   *error_ = isolate()->factory()->NewStringFromAscii(message, NOT_TENURED);
+  ASSERT(!error_->is_null());
   // Zip to the end to make sure the no more input is read.
   current_ = kEndMarker;
   next_pos_ = in()->length();
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Mon Mar 24 14:16:14 2014 UTC
+++ /branches/bleeding_edge/src/runtime.cc      Mon Mar 24 15:01:17 2014 UTC
@@ -3344,8 +3344,7 @@
         array_builder_(heap->isolate(), estimated_part_count),
         subject_(subject),
         character_count_(0),
-        is_ascii_(subject->IsOneByteRepresentation()),
-        overflowed_(false) {
+        is_ascii_(subject->IsOneByteRepresentation()) {
     // Require a non-zero initial size. Ensures that doubling the size to
     // extend the array will work.
     ASSERT(estimated_part_count > 0);
@@ -3393,11 +3392,6 @@


   Handle<String> ToString() {
-    if (overflowed_) {
-      heap_->isolate()->ThrowInvalidStringLength();
-      return Handle<String>();
-    }
-
     if (array_builder_.length() == 0) {
       return heap_->isolate()->factory()->empty_string();
     }
@@ -3405,6 +3399,7 @@
     Handle<String> joined_string;
     if (is_ascii_) {
       Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_);
+ RETURN_IF_EMPTY_HANDLE_VALUE(heap_->isolate(), seq, Handle<String>());
       DisallowHeapAllocation no_gc;
       uint8_t* char_buffer = seq->GetChars();
       StringBuilderConcatHelper(*subject_,
@@ -3415,6 +3410,7 @@
     } else {
       // Non-ASCII.
       Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
+ RETURN_IF_EMPTY_HANDLE_VALUE(heap_->isolate(), seq, Handle<String>());
       DisallowHeapAllocation no_gc;
       uc16* char_buffer = seq->GetChars();
       StringBuilderConcatHelper(*subject_,
@@ -3429,9 +3425,11 @@

   void IncrementCharacterCount(int by) {
     if (character_count_ > String::kMaxLength - by) {
-      overflowed_ = true;
+      STATIC_ASSERT(String::kMaxLength < kMaxInt);
+      character_count_ = kMaxInt;
+    } else {
+      character_count_ += by;
     }
-    character_count_ += by;
   }

  private:
@@ -3456,7 +3454,6 @@
   Handle<String> subject_;
   int character_count_;
   bool is_ascii_;
-  bool overflowed_;
 };


@@ -3913,10 +3910,13 @@
        static_cast<int64_t>(pattern_len)) *
       static_cast<int64_t>(matches) +
       static_cast<int64_t>(subject_len);
-  if (result_len_64 > INT_MAX) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+  int result_len;
+  if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) {
+    STATIC_ASSERT(String::kMaxLength < kMaxInt);
+    result_len = kMaxInt;  // Provoke exception.
+  } else {
+    result_len = static_cast<int>(result_len_64);
   }
-  int result_len = static_cast<int>(result_len_64);

   int subject_pos = 0;
   int result_pos = 0;
@@ -3929,6 +3929,7 @@
     result = Handle<ResultSeqString>::cast(
         isolate->factory()->NewRawTwoByteString(result_len));
   }
+  RETURN_IF_EMPTY_HANDLE(isolate, result);

   for (int i = 0; i < matches; i++) {
     // Copy non-matched subject content.
@@ -4108,6 +4109,7 @@
     answer = Handle<ResultSeqString>::cast(
         isolate->factory()->NewRawTwoByteString(new_length));
   }
+  ASSERT(!answer.is_null());

   int prev = 0;
   int position = 0;
@@ -6565,7 +6567,7 @@
   if (s->IsOneByteRepresentationUnderneath()) {
     Handle<SeqOneByteString> result =
         isolate->factory()->NewRawOneByteString(length);
-
+    ASSERT(!result.is_null());  // Same length as input.
     DisallowHeapAllocation no_gc;
     String::FlatContent flat_content = s->GetFlatContent();
     ASSERT(flat_content.IsFlat());
@@ -6585,6 +6587,8 @@
   } else {
     result = isolate->factory()->NewRawTwoByteString(length);
   }
+  ASSERT(!result.is_null());  // Same length as input.
+
MaybeObject* maybe = ConvertCaseHelper(isolate, *s, *result, length, mapping);
   Object* answer;
   if (!maybe->ToObject(&answer)) return maybe;
@@ -6598,6 +6602,7 @@
     if (length < 0) length = -length;
     result = isolate->factory()->NewRawTwoByteString(length);
   }
+  RETURN_IF_EMPTY_HANDLE(isolate, result);
   return ConvertCaseHelper(isolate, *s, *result, length, mapping);
 }

@@ -7242,13 +7247,16 @@
     String* element = String::cast(element_obj);
     int increment = element->length();
     if (increment > String::kMaxLength - length) {
-      return isolate->ThrowInvalidStringLength();
+      STATIC_ASSERT(String::kMaxLength < kMaxInt);
+      length = kMaxInt;  // Provoke exception;
+      break;
     }
     length += increment;
   }

   Handle<SeqTwoByteString> answer =
       isolate->factory()->NewRawTwoByteString(length);
+  RETURN_IF_EMPTY_HANDLE(isolate, answer);

   DisallowHeapAllocation no_gc;

@@ -9493,8 +9501,9 @@
   CONVERT_SMI_ARG_CHECKED(message_id, 0);
   const char* message = GetBailoutReason(
       static_cast<BailoutReason>(message_id));
-  Handle<Name> message_handle =
+  Handle<String> message_handle =
       isolate->factory()->NewStringFromAscii(CStrVector(message));
+  RETURN_IF_EMPTY_HANDLE(isolate, message_handle);
   return isolate->Throw(*message_handle);
 }

=======================================
--- /branches/bleeding_edge/src/uri.h   Thu Mar 20 12:27:36 2014 UTC
+++ /branches/bleeding_edge/src/uri.h   Mon Mar 24 15:01:17 2014 UTC
@@ -127,9 +127,11 @@

   int dest_position = 0;
   Handle<String> second_part;
+  ASSERT(unescaped_length <= String::kMaxLength);
   if (one_byte) {
     Handle<SeqOneByteString> dest =
         isolate->factory()->NewRawOneByteString(unescaped_length);
+    ASSERT(!dest.is_null());
     DisallowHeapAllocation no_allocation;
     Vector<const Char> vector = GetCharVector<Char>(string);
     for (int i = start_index; i < length; dest_position++) {
@@ -142,6 +144,7 @@
   } else {
     Handle<SeqTwoByteString> dest =
         isolate->factory()->NewRawTwoByteString(unescaped_length);
+    ASSERT(!dest.is_null());
     DisallowHeapAllocation no_allocation;
     Vector<const Char> vector = GetCharVector<Char>(string);
     for (int i = start_index; i < length; dest_position++) {
@@ -263,11 +266,7 @@

       // We don't allow strings that are longer than a maximal length.
       ASSERT(String::kMaxLength < 0x7fffffff - 6);  // Cannot overflow.
-      if (escaped_length > String::kMaxLength) {
-        AllowHeapAllocation allocate_error_and_return;
-        isolate->ThrowInvalidStringLength();
-        return Handle<String>::null();
-      }
+ if (escaped_length > String::kMaxLength) break; // Provoke exception.
     }
   }

@@ -276,6 +275,7 @@

   Handle<SeqOneByteString> dest =
       isolate->factory()->NewRawOneByteString(escaped_length);
+  RETURN_IF_EMPTY_HANDLE_VALUE(isolate, dest, Handle<String>());
   int dest_position = 0;

   { DisallowHeapAllocation no_allocation;
=======================================
--- /branches/bleeding_edge/test/cctest/cctest.status Fri Mar 21 11:45:54 2014 UTC +++ /branches/bleeding_edge/test/cctest/cctest.status Mon Mar 24 15:01:17 2014 UTC
@@ -74,6 +74,7 @@
   'test-api/Threading2': [PASS, ['mode == debug', SLOW]],
   'test-api/Threading3': [PASS, ['mode == debug', SLOW]],
   'test-api/Threading4': [PASS, ['mode == debug', SLOW]],
+  'test-strings/StringOOM*': [PASS, ['mode == debug', SLOW]],
 }],  # ALWAYS

##############################################################################
=======================================
--- /branches/bleeding_edge/test/cctest/test-strings.cc Mon Mar 24 10:07:15 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-strings.cc Mon Mar 24 15:01:17 2014 UTC
@@ -1352,3 +1352,64 @@
     CHECK_EQ(Min(upper, lower), test);
   }
 }
+
+
+class DummyResource: public v8::String::ExternalStringResource {
+ public:
+  virtual const uint16_t* data() const { return NULL; }
+  virtual size_t length() const { return 1 << 30; }
+};
+
+
+class DummyOneByteResource: public v8::String::ExternalOneByteStringResource {
+ public:
+  virtual const char* data() const { return NULL; }
+  virtual size_t length() const { return 1 << 30; }
+};
+
+
+TEST(InvalidExternalString) {
+  CcTest::InitializeVM();
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  { HandleScope scope(isolate);
+    DummyOneByteResource r;
+    CHECK(isolate->factory()->NewExternalStringFromAscii(&r).is_null());
+    CHECK(isolate->has_pending_exception());
+    isolate->clear_pending_exception();
+  }
+
+  { HandleScope scope(isolate);
+    DummyResource r;
+    CHECK(isolate->factory()->NewExternalStringFromTwoByte(&r).is_null());
+    CHECK(isolate->has_pending_exception());
+    isolate->clear_pending_exception();
+  }
+}
+
+
+#define INVALID_STRING_TEST(FUN, TYPE) \ + TEST(StringOOM##FUN) { \ + CcTest::InitializeVM(); \ + LocalContext context; \ + Isolate* isolate = CcTest::i_isolate(); \ + STATIC_ASSERT(String::kMaxLength < kMaxInt); \ + static const int invalid = String::kMaxLength + 1; \ + HandleScope scope(isolate); \ + Vector<TYPE> dummy = Vector<TYPE>::New(invalid); \ + CHECK(isolate->factory()->FUN(Vector<const TYPE>::cast(dummy)).is_null()); \ + memset(dummy.start(), 0x20, dummy.length() * sizeof(TYPE)); \ + CHECK(isolate->has_pending_exception()); \ + isolate->clear_pending_exception(); \ + dummy.Dispose(); \
+  }
+
+INVALID_STRING_TEST(NewStringFromAscii, char)
+INVALID_STRING_TEST(NewStringFromUtf8, char)
+INVALID_STRING_TEST(NewStringFromOneByte, uint8_t)
+INVALID_STRING_TEST(NewStringFromTwoByte, uint16_t)
+INVALID_STRING_TEST(InternalizeOneByteString, uint8_t)
+INVALID_STRING_TEST(InternalizeUtf8String, char)
+INVALID_STRING_TEST(InternalizeTwoByteString, uint16_t)
+
+#undef INVALID_STRING_TEST
=======================================
--- /branches/bleeding_edge/test/mjsunit/string-oom-replace-global-regexp-with-string.js Thu Mar 20 12:27:36 2014 UTC +++ /branches/bleeding_edge/test/mjsunit/string-oom-replace-global-regexp-with-string.js Mon Mar 24 15:01:17 2014 UTC
@@ -2,13 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.

+
+
 var a = 'a';
 for (var i = 0; i < 5; i++) a += a;
 var b = 'b';
 for (var i = 0; i < 23; i++) b += b;

-function replace() {
+function replace1() {
   a.replace(/./g, b);
 }

-assertThrows(replace, RangeError);
+assertThrows(replace1, RangeError);
+
+
+var a = 'a';
+for (var i = 0; i < 16; i++) a += a;
+
+function replace2() {
+  a.replace(/a/g, a);
+}
+
+assertThrows(replace2, RangeError);
=======================================
--- /branches/bleeding_edge/tools/lexer-shell.cc Mon Mar 24 14:43:41 2014 UTC +++ /branches/bleeding_edge/tools/lexer-shell.cc Mon Mar 24 15:01:17 2014 UTC
@@ -68,6 +68,7 @@
             Vector<const uint16_t>(
                 reinterpret_cast<const uint16_t*>(source_),
                 length / 2));
+        CHECK_NOT_EMPTY_HANDLE(isolate, result);
         stream_ =
new GenericStringUtf16CharacterStream(result, 0, result->length());
         break;
@@ -75,6 +76,7 @@
       case LATIN1: {
         Handle<String> result = isolate->factory()->NewStringFromOneByte(
             Vector<const uint8_t>(source_, length));
+        CHECK_NOT_EMPTY_HANDLE(isolate, result);
         stream_ =
new GenericStringUtf16CharacterStream(result, 0, result->length());
         break;

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to