No longer OOM on invalid string length.

R=ishell@chromium.org
BUG=v8:3060
LOG=Y

Review URL: https://codereview.chromium.org/207613005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20202 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-03-24 15:01:17 +00:00
parent dccd57f1ec
commit 531217502c
20 changed files with 179 additions and 49 deletions

View File

@ -5403,6 +5403,8 @@ inline Local<String> NewString(Isolate* v8_isolate,
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 @@ Local<String> v8::String::Concat(Handle<String> left, Handle<String> right) {
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 @@ Local<String> v8::String::Concat(Handle<String> left, Handle<String> right) {
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 @@ Local<Symbol> v8::Symbol::New(Isolate* isolate, const char* data, int length) {
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 @@ Handle<String> CpuProfileNode::GetFunctionName() const {
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);
}
}

View File

@ -88,6 +88,8 @@ Handle<String> Bootstrapper::NativesSourceLookup(int index) {
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 @@ bool Genesis::CompileExperimentalBuiltin(Isolate* isolate, int index) {
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 @@ bool Genesis::CompileScriptCached(Isolate* isolate,
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 @@ static Handle<JSObject> ResolveBuiltinIdHolder(
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 @@ bool Genesis::InstallExtension(Isolate* isolate,
}
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,

View File

@ -73,6 +73,7 @@ class SourceCodeCache BASE_EMBEDDED {
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_));

View File

@ -368,7 +368,7 @@ Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() {
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"));
}

View File

@ -754,6 +754,7 @@ bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
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 @@ Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
// 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_);

View File

@ -289,7 +289,7 @@ Handle<String> Factory::NewStringFromTwoByte(Vector<const uc16> string,
Handle<SeqOneByteString> Factory::NewRawOneByteString(int length,
PretenureFlag pretenure) {
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateRawOneByteString(length, pretenure),
@ -411,6 +411,7 @@ Handle<String> Factory::NewConsString(Handle<String> left,
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 @@ Handle<String> Factory::NewProperSubString(Handle<String> str,
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);

View File

@ -138,7 +138,7 @@ MaybeObject* Heap::AllocateInternalizedStringImpl(
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::AllocateOneByteInternalizedString(Vector<const uint8_t> str,
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();

View File

@ -3871,7 +3871,7 @@ MaybeObject* Heap::AllocateExternalStringFromAscii(
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 @@ MaybeObject* Heap::AllocateExternalStringFromTwoByte(
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 @@ MaybeObject* Heap::AllocateInternalizedStringImpl(
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::AllocateInternalizedStringImpl<false>(
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::AllocateRawOneByteString(int length,
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);

View File

@ -3923,9 +3923,15 @@ HInstruction* HStringAdd::New(Zone* zone,
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(

View File

@ -606,6 +606,7 @@ Handle<String> JsonParser<seq_ascii>::SlowScanJsonString(
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 @@ Handle<String> JsonParser<seq_ascii>::ScanJsonString() {
} 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_);

View File

@ -266,6 +266,7 @@ BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate)
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 @@ MaybeObject* BasicJsonStringifier::StringifyString(Isolate* isolate,
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 @@ MaybeObject* BasicJsonStringifier::StringifyString(Isolate* isolate,
} 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::ShrinkCurrentPart() {
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 @@ void BasicJsonStringifier::Extend() {
} else {
current_part_ = factory_->NewRawTwoByteString(part_length_);
}
ASSERT(!current_part_.is_null());
current_index_ = 0;
}
@ -749,6 +752,7 @@ void BasicJsonStringifier::ChangeEncoding() {
ShrinkCurrentPart();
Accumulate();
current_part_ = factory_->NewRawTwoByteString(part_length_);
ASSERT(!current_part_.is_null());
current_index_ = 0;
is_ascii_ = false;
}

View File

@ -466,6 +466,7 @@ bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re,
// 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;
}

View File

@ -2013,8 +2013,8 @@ Handle<JSArray> LiveEdit::CheckAndDropActivations(
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;

View File

@ -215,6 +215,7 @@ Handle<String> Parser::LookupCachedSymbol(int symbol_id) {
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 @@ void ParserTraits::ReportMessageAt(Scanner::Location source_location,
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 @@ Handle<String> ParserTraits::GetSymbol(Scanner* scanner) {
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 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
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 @@ bool RegExpParser::simple() {
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();

View File

@ -3344,8 +3344,7 @@ class ReplacementStringBuilder {
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 @@ class ReplacementStringBuilder {
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 @@ class ReplacementStringBuilder {
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 @@ class ReplacementStringBuilder {
} 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 @@ class ReplacementStringBuilder {
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 @@ class ReplacementStringBuilder {
Handle<String> subject_;
int character_count_;
bool is_ascii_;
bool overflowed_;
};
@ -3913,10 +3910,13 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
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 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
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 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString(
answer = Handle<ResultSeqString>::cast(
isolate->factory()->NewRawTwoByteString(new_length));
}
ASSERT(!answer.is_null());
int prev = 0;
int position = 0;
@ -6565,7 +6567,7 @@ MUST_USE_RESULT static MaybeObject* ConvertCase(
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 @@ MUST_USE_RESULT static MaybeObject* ConvertCase(
} 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 @@ MUST_USE_RESULT static MaybeObject* ConvertCase(
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 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
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 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowMessage) {
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);
}

View File

@ -127,9 +127,11 @@ Handle<String> URIUnescape::UnescapeSlow(
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 @@ Handle<String> URIUnescape::UnescapeSlow(
} 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 @@ Handle<String> URIEscape::Escape(Isolate* isolate, Handle<String> string) {
// 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<String> URIEscape::Escape(Isolate* isolate, Handle<String> string) {
Handle<SeqOneByteString> dest =
isolate->factory()->NewRawOneByteString(escaped_length);
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, dest, Handle<String>());
int dest_position = 0;
{ DisallowHeapAllocation no_allocation;

View File

@ -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
##############################################################################

View File

@ -1352,3 +1352,64 @@ TEST(Latin1IgnoreCase) {
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

View File

@ -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);

View File

@ -68,6 +68,7 @@ class BaselineScanner {
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 @@ class BaselineScanner {
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;