What's happening is: 1. We have an active Baseline stub on the stack, a Sparse GetElement stub. 2. This stub ends up calling function `f` recursively due to the `0` element getter. 3. `f` also changes `Array.prototype` to a new (proxy) object, so the original `Array.prototype` shape is now dead. 4. The Baseline CacheIR stub from (1) is still active on the stack. We trace it in `TraceWeakBaselineStubFrame => TraceCacheIRStub` where `trc->traceWeakEdges()` is false, so we don't trace the now dead shape. 5. We later call `TraceWeakCacheIRStub` where we return `false` when we notice the dead shape, but `TraceWeakBaselineStubFrame` ignores this return value. 6. Next time we trace the BaselineStub frame, we find the same stub but this shape field is now garbage and we crash. Potential fix is to always trace weak edges in `TraceCacheIRStub` when called for Baseline stub frames. That fixes the test locally. Bug 1863939 may have exposed this, but I think this goes back to bug 1837620. More reduced test: ```js function f() { try { arr.toReversed(); } catch {} var handler = {get() { return arr[0]; }}; var proxy = new Proxy(Object.prototype, handler); Object.setPrototypeOf(Array.prototype, proxy); } var arr = []; Object.defineProperty(arr, 0, {get: f}); gczeal(10); f(); ```
Bug 1888892 Comment 5 Edit History
Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.
What's happening is: 1. We have an active Baseline stub on the stack, a Sparse GetElement stub. 2. This stub ends up calling function `f` recursively due to the `0` element getter. 3. `f` also changes `Array.prototype`'s proto to a new (proxy) object, so the original `Array.prototype` shape is now dead. 4. The Baseline CacheIR stub from (1) is still active on the stack. We trace it in `TraceWeakBaselineStubFrame => TraceCacheIRStub` where `trc->traceWeakEdges()` is false, so we don't trace the now dead shape. 5. We later call `TraceWeakCacheIRStub` where we return `false` when we notice the dead shape, but `TraceWeakBaselineStubFrame` ignores this return value. 6. Next time we trace the BaselineStub frame, we find the same stub but this shape field is now garbage and we crash. Potential fix is to always trace weak edges in `TraceCacheIRStub` when called for Baseline stub frames. That fixes the test locally. Bug 1863939 may have exposed this, but I think this goes back to bug 1837620. More reduced test: ```js function f() { try { arr.toReversed(); } catch {} var handler = {get() { return arr[0]; }}; var proxy = new Proxy(Object.prototype, handler); Object.setPrototypeOf(Array.prototype, proxy); } var arr = []; Object.defineProperty(arr, 0, {get: f}); gczeal(10); f(); ```
What's happening is: 1. We have an active Baseline stub on the stack, a Sparse GetElement stub. 2. This stub ends up calling function `f` recursively due to the `0` element getter. 3. `f` also changes `Array.prototype`'s proto to a new (proxy) object, so the original `Array.prototype` shape is now dead. 4. The Baseline CacheIR stub from (1) is still active on the stack. We trace it in `TraceWeakBaselineStubFrame => TraceCacheIRStub` where `trc->traceWeakEdges()` is false, so we don't trace the now dead shape. 5. We later call `TraceWeakCacheIRStub` where we return `false` when we notice the dead shape, but `TraceWeakBaselineStubFrame` ignores this return value. 6. Next time we trace the BaselineStub frame, we find the same stub but a shape field is now garbage and we crash. Potential fix is to always trace weak edges in `TraceCacheIRStub` when called for Baseline stub frames. That fixes the test locally. Bug 1863939 may have exposed this, but I think this goes back to bug 1837620. More reduced test: ```js function f() { try { arr.toReversed(); } catch {} var handler = {get() { return arr[0]; }}; var proxy = new Proxy(Object.prototype, handler); Object.setPrototypeOf(Array.prototype, proxy); } var arr = []; Object.defineProperty(arr, 0, {get: f}); gczeal(10); f(); ```