Array.prototype.concat result length (ES5.1)

Allen Wirfs-Brock allen at wirfs-brock.com
Wed Jul 20 15:22:01 PDT 2011


Yes, liorean's analysis below seems correct.  If the final length is a value >= 2^32 then attempting to set it on an array object will throw a RangeError.  However, this special behavior is only for array objects.  If push is used generically with non-array objects then "n" can reach a greater value and the final length will be set appropriately.  Where a wrap could occur would be if the push or another similar array method was subsequently applied to such a non object with a huge length property value.   These  methods generally apply ToUnit32 to the length value when they initially retrieve it. So operations upon a non-array object with a huge length will start at some warped position. 

This is the same in both ES3 and ES5.  I'd argue that the initial ToUint32 in these algorithms is really a bug that wasn't caught long ago.  For real arrays its is unnecessary as the special internal method treatment guarantee's it is already a uint32 and is unnecessary.  For non-arrays there are the array methods don't generally  clamp either indices or length values to 32-bits on stores.  So the initial to uint32 at the beginning of these algorithms is unnecessary for real arrays and is potentially corrupting for non arrays.   It probably really should be doing a ToInteger (or perhaps the non-existent ToUInteger) to guarantee it is working with an integer length. 

I filed a change request for the ES.next draft to eliminate the uint32 length restriction on arrays.  It is https://bugs.ecmascript.org/show_bug.cgi?id=145 
https://bugs.ecmascript.org/show_bug.cgi?id=146 is a bug against the initial length conversion for non-array object in the array methods.


Allen

On Jul 18, 2011, at 2:02 PM, liorean wrote:

>> On 07/14/2011 10:04 AM, Allen Wirfs-Brock wrote:
>>> It is probably a bug, because array index based operations generally warp
>>> around to 0 at 2^32.
> 
> On 18 July 2011 19:51, Jeff Walden <jwalden+es at mit.edu> wrote:
>> Removing all the RangeError stuff, and making array indexes just
>> non-negative integers,  would be nice for ES6 or similar.  I suspect
>> changing that won't break anyone worth caring about, although I do know some
>> people have taken the time to care about this in the past (mostly in a
>> spec-nut way :-) ):
>> 
>> http://hexmen.com/blog/2006/12/push-and-pop/
> 
> Hmm. That link has the following to say:
> -----
> Steps 3 – 6 of push are a little ambiguous, and the specification
> probably should have stated that repeated increments to n must be done
> using 32-bit unsigned integer arithmetic – it’s kind-of implicit as n
> is assigned the result of the internal ToUint32 operator. Using 32-bit
> arithmetic leads to some strange edge-cases: when n overflows from
> 232-1 to 0, push will have set a property called 4294967295. This is
> strange, as 429496795 is not an array index (as discussed above), but
> at least it means the property-value will still be available after the
> inevitable array-truncation (when length is set to some small value in
> step 8.)
> ----
> 
> That is actually contrary to my reading of ECMA-262 3ed. intentions. I
> assume 5 ed. has the same intentions, but I have not checked it. The
> way I read those intentions is as you can see in the error I reported
> in my comment to:
>    http://blogs.msdn.com/b/jscript/archive/2008/03/25/performance-optimization-of-arrays-part-i.aspx
> (Opera fixed a different but related bug in the same algorithms in
> Futhark to follow the correct handling (as I read the spec). Carakan
> today I don't know about.)
> 
> For those not wanting to go searching for my comment and sifting
> through that text: The algorithm in question uses ToUInt32 to convert
> the value, but the storage is not as uint32 but as pretty much
> everywhere in ECMAScript, Number, thus follows normal double
> arithmetics. This is particularly of note as it means that it should
> not wrap around - the purpose of the following parts of 15.4.5.1
> [[Put]] (P, V):
> ----
> 12. Compute ToUint32(V).
> 
> 13. If Result(12) is not equal to ToNumber(V), throw a RangeError exception.
> 
> 14. For every integer k that is less than the value of the length
> property of A but not less than Result(12), if A itself has a property
> (not an inherited property) named ToString(k), then delete that
> property.
> 
> 15. Set the value of property P of A to Result(12).
> ----
> is to, at step 13, catch the specific event of trying to exceed uint32
> size with the length property and throw an error *instead of* wrapping
> around and as a result of step 14 of above algorithm destroy
> properties on the array. Wrapping around is an error, because ToUInt32
> gives not a uint32 but a Number which can fit into a unit32 as result.
> IIRC the 3ed. spec never uses any other number format than Number, it
> only performs the operations to fit an input Number type into the
> limitations of those other number types, into an output of Number
> type.
> -- 
> David "liorean" Andersson
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110720/d32f1de1/attachment.html>


More information about the es-discuss mailing list