Closed Bug 1350864 Opened 8 years ago Closed 8 years ago

Freezing an array does not set non-writable length correctly

Categories

(Core :: JavaScript Engine, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla55
Tracking Status
firefox55 --- fixed

People

(Reporter: jandem, Assigned: jandem)

References

Details

Attachments

(1 file)

Attached patch PatchSplinter Review
We have an invariant that arrays with non-writable length have capacity <= initializedLength, so the JITs don't have to check for non-writable length when adding new elements. However, when we freeze an array, we set the NONWRITABLE_ARRAY_LENGTH ObjectElements flag but we don't ensure capacity <= initializedLength. This is a regression from bug 1283334 and observable with inlined Array#push in Ion. The attached patch moves this code from ArraySetLength into ArrayObject::setNonWritableLength, so we can also call it from SetIntegrityLevel.
Attachment #8851564 - Flags: review?(jwalden+bmo)
Comment on attachment 8851564 [details] [diff] [review] Patch Review of attachment 8851564 [details] [diff] [review]: ----------------------------------------------------------------- > We have an invariant that arrays with non-writable length have > capacity <= initializedLength, so the JITs don't have to check > for non-writable length when adding new elements. You meant capacity <= length, right? I'm pretty sure initializedLength <= capacity is the *actual* invariant between these two fields. Despite that flub, the patch does seem to actually be implementing the real invariant. ::: js/src/jit-test/tests/ion/array-push-frozen-array.js @@ +11,5 @@ > + try { > + arr.push(2); > + assertEq(i <= 1500, true); > + } catch(e) { > + assertEq(e.toString().includes("non-writable length"), true); I'd prefer if you just checked for instanceof TypeError, to not depend on error messages that might change. ::: js/src/vm/ArrayObject.h @@ +42,5 @@ > + if (getElementsHeader()->capacity > len) { > + shrinkElements(cx, len); > + getElementsHeader()->capacity = len; > + } > + getElementsHeader()->setNonwritableArrayLength(); A |ObjectElements* header = getElementsHeader();| local would be better than calling the function multiple times, IMO. ::: js/src/vm/NativeObject.h @@ +231,5 @@ > return flags & NONWRITABLE_ARRAY_LENGTH; > } > void setNonwritableArrayLength() { > + // See ArrayObject::setNonWritableLength. > + MOZ_ASSERT(capacity <= initializedLength); Mm. I wish this could be folded directly into ArrayObject::setNonWritableArrayLength, while still preserving its encapsulation of flags-modification, given that's the only caller now. :-\ Based on that being the only caller, and in light of the existing invariants on initializedLength/capacity/length, this should flatly assert |capacity == initializedLength|.
Attachment #8851564 - Flags: review?(jwalden+bmo) → review+
Pushed by jandemooij@gmail.com: https://hg.mozilla.org/integration/mozilla-inbound/rev/e03b31080750 Fix SetIntegrityLevel to set non-writable length correctly when freezing arrays. r=Waldo
Status: ASSIGNED → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla55
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: