Reproduction
new Set().intersection({ get has() { throw 0; }, size: -0.5 });
Expected
The has getter runs and the 0 it throws propagates.
V8 (15.6.20):
d8> new Set().intersection({ get has() { throw 0; }, size: -0.5 });
unnamed:1: 0
new Set().intersection({ get has() { throw 0; }, size: -0.5 })
^
Actual (QuickJS-ng)
A RangeError is thrown before has is ever read.
qjs > new Set().intersection({ get has() { throw 0; }, size: -0.5 });
RangeError: .size is not a legal size
Spec
GetSetRecord converts rawSize through ToIntegerOrInfinity and only then tests the result against zero. ToIntegerOrInfinity truncates toward zero, so -0.5 becomes 0, the negative test fails, and the RangeError step is never reached. has is read after that test, so the getter must run.
QuickJS is correct for size: -1, which truncates to -1 and does throw. The defect is limited to values in (-1, 0), where truncation removes the sign.
Versions
- QuickJS-ng: 0.17.0
- V8: 15.6.20
Reproduction
Expected
The
hasgetter runs and the0it throws propagates.V8 (15.6.20):
Actual (QuickJS-ng)
A RangeError is thrown before
hasis ever read.Spec
GetSetRecordconvertsrawSizethroughToIntegerOrInfinityand only then tests the result against zero.ToIntegerOrInfinitytruncates toward zero, so-0.5becomes0, the negative test fails, and the RangeError step is never reached.hasis read after that test, so the getter must run.QuickJS is correct for
size: -1, which truncates to-1and does throw. The defect is limited to values in(-1, 0), where truncation removes the sign.Versions