Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions JSTests/stress/dfg-parseIntResult-should-not-wrap-above-int32.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// parseInt results outside int32 range must be boxed as doubles, not
// sign-wrapped int32s, once the call site tiers up to the DFG/FTL.
// parseIntResult() used to do static_cast<int>(input) before the round-trip
// comparison deciding int32 vs double boxing; the cast is undefined behavior
// for out-of-range inputs, which let LTO fold the overflow guard away.

function hex(s) {
return parseInt(s, 16);
}
noInline(hex);

function dec(s) {
return parseInt(s);
}
noInline(dec);

const hugeHex = "f".repeat(400);

for (let i = 0; i < testLoopCount; ++i) {
let v = hex("80000000");
if (v !== 2147483648)
throw "FAILED: parseInt('80000000', 16) === " + v + " at iteration " + i;
v = hex("ffffffff");
if (v !== 4294967295)
throw "FAILED: parseInt('ffffffff', 16) === " + v + " at iteration " + i;
v = hex("7fffffff");
if (v !== 2147483647)
throw "FAILED: parseInt('7fffffff', 16) === " + v + " at iteration " + i;
v = hex("-80000001");
if (v !== -2147483649)
throw "FAILED: parseInt('-80000001', 16) === " + v + " at iteration " + i;
v = dec("2147483648");
if (v !== 2147483648)
throw "FAILED: parseInt('2147483648') === " + v + " at iteration " + i;
v = hex(hugeHex); // overflows to Infinity
if (v !== Infinity)
throw "FAILED: parseInt('f'.repeat(400), 16) === " + v + " at iteration " + i;
}
56 changes: 56 additions & 0 deletions JSTests/stress/switch-imm-scrutinee-above-int32.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// A double scrutinee outside int32 range must never match an immediate
// switch case. slow_path_switch_imm used to do static_cast<int32_t>(value)
// — undefined behavior for out-of-range doubles — before the range check;
// a UB-exploiting optimizer could then fold the check away and match the
// case whose label equals the wrapped/saturated conversion result.

function bigSwitch(x) {
switch (x) {
case -2147483648:
return "int32-min";
case 2147483647:
return "int32-max";
case 0:
return "zero";
default:
return "default";
}
}
noInline(bigSwitch);

function denseSwitch(x) {
// Dense enough for a jump table (SwitchType::Immediate).
switch (x) {
case -2147483648: return 0;
case -2147483647: return 1;
case -2147483646: return 2;
case -2147483645: return 3;
case -2147483644: return 4;
case -2147483643: return 5;
case -2147483642: return 6;
case -2147483641: return 7;
default: return -1;
}
}
noInline(denseSwitch);

for (let i = 0; i < testLoopCount; ++i) {
let r = bigSwitch(2147483648); // 2^31, truncates to INT32_MIN on x86
if (r !== "default")
throw "FAILED: bigSwitch(2^31) === " + r + " at iteration " + i;
r = bigSwitch(4294967296); // 2^32, truncates to 0 via modular wrap
if (r !== "default")
throw "FAILED: bigSwitch(2^32) === " + r + " at iteration " + i;
r = bigSwitch(Infinity);
if (r !== "default")
throw "FAILED: bigSwitch(Infinity) === " + r + " at iteration " + i;
r = bigSwitch(-2147483648);
if (r !== "int32-min")
throw "FAILED: bigSwitch(-2^31) === " + r + " at iteration " + i;
r = denseSwitch(2147483648);
if (r !== -1)
throw "FAILED: denseSwitch(2^31) === " + r + " at iteration " + i;
r = denseSwitch(-2147483648);
if (r !== 0)
throw "FAILED: denseSwitch(-2^31) === " + r + " at iteration " + i;
}
Loading