Skip to content

Commit 0f245d2

Browse files
ChALkeRclaudedeepview-autofix
committed
lib: fix modulo sign in webidl convertToInt
The modulo() helper in lib/internal/webidl.js is documented to implement ECMA-262's "x modulo y" (result has the same sign as y), but it used the JS % operator directly, whose result takes the sign of x. convertToInt step 10 relies on modulo(x, 2^bitLength) producing a non-negative representative in [0, 2^bitLength); step 11 only handles the signed upper half, so negative results of % were returned unchanged. As a result, negative inputs to unsigned WebIDL integer types returned the original negative value instead of the two's-complement wrap (e.g. convertToInt('v', -3, 8) returned -3 instead of 253), and signed inputs in the one-wrap band below the lower bound were returned as-is (convertToInt('v', -200, 8, { signed: true }) returned -200 instead of 56). This diverged from typed-array coercion. Co-Authored-By: Claude <[email protected]> Co-Authored-By: DeepView Autofix <[email protected]> Co-Authored-By: Nikita Skovoroda <[email protected]> Assisted-by: Claude <[email protected]> Signed-off-by: Nikita Skovoroda <[email protected]>
1 parent 4744070 commit 0f245d2

2 files changed

Lines changed: 12 additions & 0 deletions

File tree

lib/internal/webidl.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,14 @@ function pow2(exponent) {
108108

109109
// https://tc39.es/ecma262/#eqn-modulo
110110
// The notation “x modulo y” computes a value k of the same sign as y.
111+
// As y is always positive in this file, we can do a simple r < 0 check for that.
111112
function modulo(x, y) {
112113
const r = x % y;
113114
// Convert -0 to +0.
114115
if (r === 0) {
115116
return 0;
117+
} else if (r < 0) {
118+
return r + y;
116119
}
117120
return r;
118121
}

test/parallel/test-internal-webidl-converttoint.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,12 @@ assert.strictEqual(convertToInt('x', 0xFFFF_FFFF, 32), 0xFFFF_FFFF);
5656
// Out of range, step 11.
5757
assert.strictEqual(convertToInt('x', 0x8000_0000, 32, { signed: true }), -0x8000_0000);
5858
assert.strictEqual(convertToInt('x', 0xFFF_FFFF, 32, { signed: true }), 0xFFF_FFFF);
59+
60+
// Negative values must wrap as two's-complement, matching typed-array behavior.
61+
assert.strictEqual(convertToInt('x', -3, 8), 253);
62+
assert.strictEqual(convertToInt('x', -3, 8), new Uint8Array([-3])[0]);
63+
assert.strictEqual(convertToInt('x', -1, 32), 0xFFFF_FFFF);
64+
assert.strictEqual(convertToInt('x', -1, 32), new Uint32Array([-1])[0]);
65+
assert.strictEqual(convertToInt('x', -200, 8, { signed: true }), 56);
66+
assert.strictEqual(convertToInt('x', -200, 8, { signed: true }),
67+
new Int8Array([-200])[0]);

0 commit comments

Comments
 (0)