Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(326)

Side by Side Diff: src/runtime.cc

Issue 525064: Fixed potential length miscalculations by limiting max size of arrays and strings. (Closed)
Patch Set: Added (unrelated) cast to make Win64 compile. Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/objects.cc ('k') | src/utils.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 5353 matching lines...) Expand 10 before | Expand all | Expand 10 after
5364 */ 5364 */
5365 class ArrayConcatVisitor { 5365 class ArrayConcatVisitor {
5366 public: 5366 public:
5367 ArrayConcatVisitor(Handle<FixedArray> storage, 5367 ArrayConcatVisitor(Handle<FixedArray> storage,
5368 uint32_t index_limit, 5368 uint32_t index_limit,
5369 bool fast_elements) : 5369 bool fast_elements) :
5370 storage_(storage), index_limit_(index_limit), 5370 storage_(storage), index_limit_(index_limit),
5371 fast_elements_(fast_elements), index_offset_(0) { } 5371 fast_elements_(fast_elements), index_offset_(0) { }
5372 5372
5373 void visit(uint32_t i, Handle<Object> elm) { 5373 void visit(uint32_t i, Handle<Object> elm) {
5374 uint32_t index = i + index_offset_; 5374 if (i >= index_limit_ - index_offset_) return;
5375 if (index >= index_limit_) return; 5375 uint32_t index = index_offset_ + i;
5376 5376
5377 if (fast_elements_) { 5377 if (fast_elements_) {
5378 ASSERT(index < static_cast<uint32_t>(storage_->length())); 5378 ASSERT(index < static_cast<uint32_t>(storage_->length()));
5379 storage_->set(index, *elm); 5379 storage_->set(index, *elm);
5380 5380
5381 } else { 5381 } else {
5382 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_); 5382 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
5383 Handle<NumberDictionary> result = 5383 Handle<NumberDictionary> result =
5384 Factory::DictionaryAtNumberPut(dict, index, elm); 5384 Factory::DictionaryAtNumberPut(dict, index, elm);
5385 if (!result.is_identical_to(dict)) 5385 if (!result.is_identical_to(dict))
5386 storage_ = result; 5386 storage_ = result;
5387 } 5387 }
5388 } 5388 }
5389 5389
5390 void increase_index_offset(uint32_t delta) { 5390 void increase_index_offset(uint32_t delta) {
5391 index_offset_ += delta; 5391 if (index_limit_ - index_offset_ < delta) {
5392 index_offset_ = index_limit_;
5393 } else {
5394 index_offset_ += delta;
5395 }
5392 } 5396 }
5393 5397
5394 Handle<FixedArray> storage() { return storage_; } 5398 Handle<FixedArray> storage() { return storage_; }
5395 5399
5396 private: 5400 private:
5397 Handle<FixedArray> storage_; 5401 Handle<FixedArray> storage_;
5402 // Limit on the accepted indices. Elements with indices larger than the
5403 // limit are ignored by the visitor.
5398 uint32_t index_limit_; 5404 uint32_t index_limit_;
5405 // Index after last seen index. Always less than or equal to index_limit_.
5406 uint32_t index_offset_;
5399 bool fast_elements_; 5407 bool fast_elements_;
5400 uint32_t index_offset_;
5401 }; 5408 };
5402 5409
5403 5410
5404 template<class ExternalArrayClass, class ElementType> 5411 template<class ExternalArrayClass, class ElementType>
5405 static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver, 5412 static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
5406 bool elements_are_ints, 5413 bool elements_are_ints,
5407 bool elements_are_guaranteed_smis, 5414 bool elements_are_guaranteed_smis,
5408 uint32_t range, 5415 uint32_t range,
5409 ArrayConcatVisitor* visitor) { 5416 ArrayConcatVisitor* visitor) {
5410 Handle<ExternalArrayClass> array( 5417 Handle<ExternalArrayClass> array(
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
5562 5569
5563 /** 5570 /**
5564 * A helper function that visits elements of an Array object, and elements 5571 * A helper function that visits elements of an Array object, and elements
5565 * on its prototypes. 5572 * on its prototypes.
5566 * 5573 *
5567 * Elements on prototypes are visited first, and only elements whose indices 5574 * Elements on prototypes are visited first, and only elements whose indices
5568 * less than Array length are visited. 5575 * less than Array length are visited.
5569 * 5576 *
5570 * If a ArrayConcatVisitor object is given, the visitor is called with 5577 * If a ArrayConcatVisitor object is given, the visitor is called with
5571 * parameters, element's index + visitor_index_offset and the element. 5578 * parameters, element's index + visitor_index_offset and the element.
5579 *
5580 * The returned number of elements is an upper bound on the actual number
5581 * of elements added. If the same element occurs in more than one object
5582 * in the array's prototype chain, it will be counted more than once, but
5583 * will only occur once in the result.
5572 */ 5584 */
5573 static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array, 5585 static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
5574 ArrayConcatVisitor* visitor) { 5586 ArrayConcatVisitor* visitor) {
5575 uint32_t range = static_cast<uint32_t>(array->length()->Number()); 5587 uint32_t range = static_cast<uint32_t>(array->length()->Number());
5576 Handle<Object> obj = array; 5588 Handle<Object> obj = array;
5577 5589
5578 static const int kEstimatedPrototypes = 3; 5590 static const int kEstimatedPrototypes = 3;
5579 List< Handle<JSObject> > objects(kEstimatedPrototypes); 5591 List< Handle<JSObject> > objects(kEstimatedPrototypes);
5580 5592
5581 // Visit prototype first. If an element on the prototype is shadowed by 5593 // Visit prototype first. If an element on the prototype is shadowed by
5582 // the inheritor using the same index, the ArrayConcatVisitor visits 5594 // the inheritor using the same index, the ArrayConcatVisitor visits
5583 // the prototype element before the shadowing element. 5595 // the prototype element before the shadowing element.
5584 // The visitor can simply overwrite the old value by new value using 5596 // The visitor can simply overwrite the old value by new value using
5585 // the same index. This follows Array::concat semantics. 5597 // the same index. This follows Array::concat semantics.
5586 while (!obj->IsNull()) { 5598 while (!obj->IsNull()) {
5587 objects.Add(Handle<JSObject>::cast(obj)); 5599 objects.Add(Handle<JSObject>::cast(obj));
5588 obj = Handle<Object>(obj->GetPrototype()); 5600 obj = Handle<Object>(obj->GetPrototype());
5589 } 5601 }
5590 5602
5591 uint32_t nof_elements = 0; 5603 uint32_t nof_elements = 0;
5592 for (int i = objects.length() - 1; i >= 0; i--) { 5604 for (int i = objects.length() - 1; i >= 0; i--) {
5593 Handle<JSObject> obj = objects[i]; 5605 Handle<JSObject> obj = objects[i];
5594 nof_elements += 5606 uint32_t encountered_elements =
5595 IterateElements(Handle<JSObject>::cast(obj), range, visitor); 5607 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
5608
5609 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
5610 nof_elements = JSObject::kMaxElementCount;
5611 } else {
5612 nof_elements += encountered_elements;
5613 }
5596 } 5614 }
5597 5615
5598 return nof_elements; 5616 return nof_elements;
5599 } 5617 }
5600 5618
5601 5619
5602 /** 5620 /**
5603 * A helper function of Runtime_ArrayConcat. 5621 * A helper function of Runtime_ArrayConcat.
5604 * 5622 *
5605 * The first argument is an Array of arrays and objects. It is the 5623 * The first argument is an Array of arrays and objects. It is the
5606 * same as the arguments array of Array::concat JS function. 5624 * same as the arguments array of Array::concat JS function.
5607 * 5625 *
5608 * If an argument is an Array object, the function visits array 5626 * If an argument is an Array object, the function visits array
5609 * elements. If an argument is not an Array object, the function 5627 * elements. If an argument is not an Array object, the function
5610 * visits the object as if it is an one-element array. 5628 * visits the object as if it is an one-element array.
5611 * 5629 *
5612 * If the result array index overflows 32-bit integer, the rounded 5630 * If the result array index overflows 32-bit unsigned integer, the rounded
5613 * non-negative number is used as new length. For example, if one 5631 * non-negative number is used as new length. For example, if one
5614 * array length is 2^32 - 1, second array length is 1, the 5632 * array length is 2^32 - 1, second array length is 1, the
5615 * concatenated array length is 0. 5633 * concatenated array length is 0.
5634 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
5635 * is one more than the last array index to get a value assigned).
5616 */ 5636 */
5617 static uint32_t IterateArguments(Handle<JSArray> arguments, 5637 static uint32_t IterateArguments(Handle<JSArray> arguments,
5618 ArrayConcatVisitor* visitor) { 5638 ArrayConcatVisitor* visitor) {
5639 const uint32_t max_length = JSObject::kMaxElementCount;
5619 uint32_t visited_elements = 0; 5640 uint32_t visited_elements = 0;
5620 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); 5641 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
5621 5642
5622 for (uint32_t i = 0; i < num_of_args; i++) { 5643 for (uint32_t i = 0; i < num_of_args; i++) {
5623 Handle<Object> obj(arguments->GetElement(i)); 5644 Handle<Object> obj(arguments->GetElement(i));
5624 if (obj->IsJSArray()) { 5645 if (obj->IsJSArray()) {
5625 Handle<JSArray> array = Handle<JSArray>::cast(obj); 5646 Handle<JSArray> array = Handle<JSArray>::cast(obj);
5626 uint32_t len = static_cast<uint32_t>(array->length()->Number()); 5647 uint32_t len = static_cast<uint32_t>(array->length()->Number());
5627 uint32_t nof_elements = 5648 uint32_t nof_elements =
5628 IterateArrayAndPrototypeElements(array, visitor); 5649 IterateArrayAndPrototypeElements(array, visitor);
5629 // Total elements of array and its prototype chain can be more than 5650 // Total elements of array and its prototype chain can be more than
5630 // the array length, but ArrayConcat can only concatenate at most 5651 // the array length, but ArrayConcat can only concatenate at most
5631 // the array length number of elements. 5652 // the array length number of elements. We use the length as an estimate
5632 visited_elements += (nof_elements > len) ? len : nof_elements; 5653 // for the actual number of elements added.
5654 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
5655 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
5656 visited_elements = JSArray::kMaxElementCount;
5657 } else {
5658 visited_elements += added_elements;
5659 }
5633 if (visitor) visitor->increase_index_offset(len); 5660 if (visitor) visitor->increase_index_offset(len);
5634
5635 } else { 5661 } else {
5636 if (visitor) { 5662 if (visitor) {
5637 visitor->visit(0, obj); 5663 visitor->visit(0, obj);
5638 visitor->increase_index_offset(1); 5664 visitor->increase_index_offset(1);
5639 } 5665 }
5640 visited_elements++; 5666 if (visited_elements < JSArray::kMaxElementCount) {
5667 visited_elements++;
5668 }
5641 } 5669 }
5642 } 5670 }
5643 return visited_elements; 5671 return visited_elements;
5644 } 5672 }
5645 5673
5646 5674
5647 /** 5675 /**
5648 * Array::concat implementation. 5676 * Array::concat implementation.
5649 * See ECMAScript 262, 15.4.4.4. 5677 * See ECMAScript 262, 15.4.4.4.
5678 * TODO(lrn): Fix non-compliance for very large concatenations and update to
5679 * following the ECMAScript 5 specification.
5650 */ 5680 */
5651 static Object* Runtime_ArrayConcat(Arguments args) { 5681 static Object* Runtime_ArrayConcat(Arguments args) {
5652 ASSERT(args.length() == 1); 5682 ASSERT(args.length() == 1);
5653 HandleScope handle_scope; 5683 HandleScope handle_scope;
5654 5684
5655 CONVERT_CHECKED(JSArray, arg_arrays, args[0]); 5685 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
5656 Handle<JSArray> arguments(arg_arrays); 5686 Handle<JSArray> arguments(arg_arrays);
5657 5687
5658 // Pass 1: estimate the number of elements of the result 5688 // Pass 1: estimate the number of elements of the result
5659 // (it could be more than real numbers if prototype has elements). 5689 // (it could be more than real numbers if prototype has elements).
5660 uint32_t result_length = 0; 5690 uint32_t result_length = 0;
5661 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); 5691 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
5662 5692
5663 { AssertNoAllocation nogc; 5693 { AssertNoAllocation nogc;
5664 for (uint32_t i = 0; i < num_of_args; i++) { 5694 for (uint32_t i = 0; i < num_of_args; i++) {
5665 Object* obj = arguments->GetElement(i); 5695 Object* obj = arguments->GetElement(i);
5696 uint32_t length_estimate;
5666 if (obj->IsJSArray()) { 5697 if (obj->IsJSArray()) {
5667 result_length += 5698 length_estimate =
5668 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number()); 5699 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
5669 } else { 5700 } else {
5670 result_length++; 5701 length_estimate = 1;
5671 } 5702 }
5703 if (JSObject::kMaxElementCount - result_length < length_estimate) {
5704 result_length = JSObject::kMaxElementCount;
5705 break;
5706 }
5707 result_length += length_estimate;
5672 } 5708 }
5673 } 5709 }
5674 5710
5675 // Allocate an empty array, will set length and content later. 5711 // Allocate an empty array, will set length and content later.
5676 Handle<JSArray> result = Factory::NewJSArray(0); 5712 Handle<JSArray> result = Factory::NewJSArray(0);
5677 5713
5678 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL); 5714 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
5679 // If estimated number of elements is more than half of length, a 5715 // If estimated number of elements is more than half of length, a
5680 // fixed array (fast case) is more time and space-efficient than a 5716 // fixed array (fast case) is more time and space-efficient than a
5681 // dictionary. 5717 // dictionary.
(...skipping 2345 matching lines...) Expand 10 before | Expand all | Expand 10 after
8027 } else { 8063 } else {
8028 // Handle last resort GC and make sure to allow future allocations 8064 // Handle last resort GC and make sure to allow future allocations
8029 // to grow the heap without causing GCs (if possible). 8065 // to grow the heap without causing GCs (if possible).
8030 Counters::gc_last_resort_from_js.Increment(); 8066 Counters::gc_last_resort_from_js.Increment();
8031 Heap::CollectAllGarbage(false); 8067 Heap::CollectAllGarbage(false);
8032 } 8068 }
8033 } 8069 }
8034 8070
8035 8071
8036 } } // namespace v8::internal 8072 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.cc ('k') | src/utils.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698