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:
parent
dccd57f1ec
commit
531217502c
24
src/api.cc
24
src/api.cc
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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_));
|
||||
|
@ -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"));
|
||||
}
|
||||
|
||||
|
@ -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_);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
12
src/heap.cc
12
src/heap.cc
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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_);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
10
src/uri.h
10
src/uri.h
@ -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;
|
||||
|
@ -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
|
||||
|
||||
##############################################################################
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user