From 3654b3b2c0831bd04cf01aa83d2130d3b5badfdb Mon Sep 17 00:00:00 2001 From: "jkummerow@chromium.org" Date: Thu, 24 Apr 2014 11:11:30 +0000 Subject: [PATCH] Harden more runtime functions. R=dslomov@chromium.org, dslomov@google.com Review URL: https://codereview.chromium.org/258473004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20936 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arraybuffer.js | 4 +-- src/runtime.cc | 92 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/src/arraybuffer.js b/src/arraybuffer.js index 07924e4..796017f 100644 --- a/src/arraybuffer.js +++ b/src/arraybuffer.js @@ -40,7 +40,7 @@ function ArrayBufferConstructor(length) { // length = 1 } } -function ArrayBufferGetByteLength() { +function ArrayBufferGetByteLen() { if (!IS_ARRAYBUFFER(this)) { throw MakeTypeError('incompatible_method_receiver', ['ArrayBuffer.prototype.byteLength', this]); @@ -99,7 +99,7 @@ function SetUpArrayBuffer() { // Set up the constructor property on the ArrayBuffer prototype object. %SetProperty($ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM); - InstallGetter($ArrayBuffer.prototype, "byteLength", ArrayBufferGetByteLength); + InstallGetter($ArrayBuffer.prototype, "byteLength", ArrayBufferGetByteLen); InstallFunctions($ArrayBuffer, DONT_ENUM, $Array( "isView", ArrayBufferIsView diff --git a/src/runtime.cc b/src/runtime.cc index 812d1da..42535be 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -871,6 +871,10 @@ RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) { ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1); + if (!holder->byte_length()->IsUndefined()) { + // ArrayBuffer is already initialized; probably a fuzz test. + return *holder; + } size_t allocated_length = 0; if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) { return isolate->Throw( @@ -1055,7 +1059,7 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) { CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); CONVERT_SMI_ARG_CHECKED(arrayId, 1); CONVERT_ARG_HANDLE_CHECKED(Object, source, 2); - CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3); ASSERT(holder->GetInternalFieldCount() == v8::ArrayBufferView::kInternalFieldCount); @@ -1079,7 +1083,8 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) { JSTypedArray::cast(*source)->type() == array_type) { length_obj = Handle(JSTypedArray::cast(*source)->length(), isolate); } - size_t length = NumberToSize(isolate, *length_obj); + size_t length = 0; + RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length)); if ((length > static_cast(Smi::kMaxValue)) || (length > (kMaxInt / element_size))) { @@ -1191,17 +1196,17 @@ enum TypedArraySetResultCodes { RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) { HandleScope scope(isolate); ASSERT(args.length() == 3); - CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, source_obj, 1); - CONVERT_ARG_HANDLE_CHECKED(Object, offset_obj, 2); - - if (!target_obj->IsJSTypedArray()) + if (!args[0]->IsJSTypedArray()) return isolate->Throw(*isolate->factory()->NewTypeError( "not_typed_array", HandleVector(NULL, 0))); - if (!source_obj->IsJSTypedArray()) + if (!args[1]->IsJSTypedArray()) return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY); + CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0); + CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2); + Handle target(JSTypedArray::cast(*target_obj)); Handle source(JSTypedArray::cast(*source_obj)); size_t offset = NumberToSize(isolate, *offset_obj); @@ -1260,23 +1265,31 @@ RUNTIME_FUNCTION(Runtime_DataViewInitialize) { ASSERT(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1); - CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2); - CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3); ASSERT(holder->GetInternalFieldCount() == v8::ArrayBufferView::kInternalFieldCount); for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { holder->SetInternalField(i, Smi::FromInt(0)); } + size_t buffer_length = 0; + size_t offset = 0; + size_t length = 0; + RUNTIME_ASSERT( + TryNumberToSize(isolate, buffer->byte_length(), &buffer_length)); + RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset)); + RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length)); + + // TODO(jkummerow): When we have a "safe numerics" helper class, use it here. + // Entire range [offset, offset + length] must be in bounds. + RUNTIME_ASSERT(offset <= buffer_length); + RUNTIME_ASSERT(offset + length <= buffer_length); + // No overflow. + RUNTIME_ASSERT(offset + length >= offset); holder->set_buffer(*buffer); - ASSERT(byte_offset->IsNumber()); - ASSERT( - NumberToSize(isolate, buffer->byte_length()) >= - NumberToSize(isolate, *byte_offset) - + NumberToSize(isolate, *byte_length)); holder->set_byte_offset(*byte_offset); - ASSERT(byte_length->IsNumber()); holder->set_byte_length(*byte_length); holder->set_weak_next(buffer->weak_first_view()); @@ -1582,8 +1595,8 @@ RUNTIME_FUNCTION(Runtime_SetCreateIterator) { ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); CONVERT_SMI_ARG_CHECKED(kind, 1) - ASSERT(kind == JSSetIterator::kKindValues - || kind == JSSetIterator::kKindEntries); + RUNTIME_ASSERT(kind == JSSetIterator::kKindValues || + kind == JSSetIterator::kKindEntries); Handle table(OrderedHashSet::cast(holder->table())); return *JSSetIterator::Create(table, kind); } @@ -3097,11 +3110,8 @@ RUNTIME_FUNCTION(Runtime_SetCode) { ASSERT(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); - CONVERT_ARG_HANDLE_CHECKED(Object, code, 1); + CONVERT_ARG_HANDLE_CHECKED(JSFunction, source, 1); - if (code->IsNull()) return *target; - RUNTIME_ASSERT(code->IsJSFunction()); - Handle source = Handle::cast(code); Handle target_shared(target->shared()); Handle source_shared(source->shared()); @@ -4296,7 +4306,7 @@ RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) { CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); - ASSERT(regexp->GetFlags().is_global()); + RUNTIME_ASSERT(regexp->GetFlags().is_global()); subject = String::Flatten(subject); @@ -7231,6 +7241,12 @@ RUNTIME_FUNCTION(Runtime_StringBuilderConcat) { CONVERT_SMI_ARG_CHECKED(array_length, 1); CONVERT_ARG_HANDLE_CHECKED(String, special, 2); + size_t actual_array_length = 0; + RUNTIME_ASSERT( + TryNumberToSize(isolate, array->length(), &actual_array_length)); + RUNTIME_ASSERT(array_length >= 0); + RUNTIME_ASSERT(static_cast(array_length) <= actual_array_length); + // This assumption is used by the slice encoding in one or two smis. ASSERT(Smi::kMaxValue >= String::kMaxLength); @@ -7599,7 +7615,8 @@ RUNTIME_FUNCTION(Runtime_NumberCompare) { CONVERT_DOUBLE_ARG_CHECKED(x, 0); CONVERT_DOUBLE_ARG_CHECKED(y, 1); - if (std::isnan(x) || std::isnan(y)) return args[2]; + CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2) + if (std::isnan(x) || std::isnan(y)) return *uncomparable_result; if (x == y) return Smi::FromInt(EQUAL); if (isless(x, y)) return Smi::FromInt(LESS); return Smi::FromInt(GREATER); @@ -7887,15 +7904,15 @@ RUNTIME_FUNCTION(RuntimeHidden_MathPow) { RUNTIME_FUNCTION(Runtime_RoundNumber) { HandleScope scope(isolate); ASSERT(args.length() == 1); + CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0); isolate->counters()->math_round()->Increment(); - if (!args[0]->IsHeapNumber()) { - // Must be smi. Return the argument unchanged for all the other types - // to make fuzz-natives test happy. - return args[0]; + if (!input->IsHeapNumber()) { + ASSERT(input->IsSmi()); + return *input; } - HeapNumber* number = reinterpret_cast(args[0]); + Handle number = Handle::cast(input); double value = number->value(); int exponent = number->get_exponent(); @@ -7917,7 +7934,7 @@ RUNTIME_FUNCTION(Runtime_RoundNumber) { // If the magnitude is big enough, there's no place for fraction part. If we // try to add 0.5 to this number, 1.0 will be added instead. if (exponent >= 52) { - return number; + return *number; } if (sign && value >= -0.5) return isolate->heap()->minus_zero_value(); @@ -9666,22 +9683,22 @@ RUNTIME_FUNCTION(Runtime_DateParseString) { JSObject::EnsureCanContainHeapObjectElements(output); RUNTIME_ASSERT(output->HasFastObjectElements()); + Handle output_array(FixedArray::cast(output->elements())); + RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); str = String::Flatten(str); DisallowHeapAllocation no_gc; - FixedArray* output_array = FixedArray::cast(output->elements()); - RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); bool result; String::FlatContent str_content = str->GetFlatContent(); if (str_content.IsAscii()) { result = DateParser::Parse(str_content.ToOneByteVector(), - output_array, + *output_array, isolate->unicode_cache()); } else { ASSERT(str_content.IsTwoByte()); result = DateParser::Parse(str_content.ToUC16Vector(), - output_array, + *output_array, isolate->unicode_cache()); } @@ -13473,6 +13490,9 @@ RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) { CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0); CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1); CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2); + RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo()); + RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo()); + RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo()); LiveEdit::ReplaceRefToNestedFunction( parent_wrapper, orig_wrapper, subst_wrapper); @@ -14547,6 +14567,8 @@ RUNTIME_FUNCTION(Runtime_LoadMutableDouble) { if (idx < 0) { idx = -idx + object->map()->inobject_properties() - 1; } + Handle raw_value(object->RawFastPropertyAt(idx), isolate); + RUNTIME_ASSERT(raw_value->IsNumber() || raw_value->IsUninitialized()); return *JSObject::FastPropertyAt(object, Representation::Double(), idx); } @@ -14892,7 +14914,7 @@ RUNTIME_FUNCTION(Runtime_IsAccessAllowedForObserver) { ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1); - ASSERT(object->map()->is_access_check_needed()); + RUNTIME_ASSERT(object->map()->is_access_check_needed()); CONVERT_ARG_HANDLE_CHECKED(Object, key, 2); SaveContext save(isolate); isolate->set_context(observer->context()); -- 2.7.4