Skip to content

Commit d2e8178

Browse files
deepview-autofixclaudeChALkeR
authored
fix(webidl): correct signed integer bounds in ConvertToInt (#5038)
The signed integer lower bound was computed as `Math.pow(-2, bitLength) - 1`, which evaluates to `(-2)^bitLength - 1` instead of the spec-required `-2^(bitLength - 1)`. The step 11 overflow threshold similarly used `2^bitLength - 1` instead of `2^(bitLength - 1)`, causing values in `[2^(bitLength-1), 2^bitLength - 2]` to skip the signed wrap. Fix both expressions and update the surrounding comments to match the WebIDL spec. Signed-off-by: Nikita Skovoroda <chalkerx@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Nikita Skovoroda <chalkerx@gmail.com>
1 parent a6f8644 commit d2e8178

2 files changed

Lines changed: 24 additions & 5 deletions

File tree

lib/web/webidl/index.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,10 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, flags) {
188188
} else {
189189
// 3. Otherwise:
190190

191-
// 1. Let lowerBound be -2^bitLength − 1.
192-
lowerBound = Math.pow(-2, bitLength) - 1
191+
// 1. Let lowerBound be -2^(bitLength − 1).
192+
lowerBound = -Math.pow(2, bitLength - 1)
193193

194-
// 2. Let upperBound be 2^bitLength − 1 − 1.
194+
// 2. Let upperBound be 2^(bitLength − 1) − 1.
195195
upperBound = Math.pow(2, bitLength - 1) - 1
196196
}
197197

@@ -270,9 +270,9 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, flags) {
270270
// 10. Set x to x modulo 2^bitLength.
271271
x = x % Math.pow(2, bitLength)
272272

273-
// 11. If signedness is "signed" and x ≥ 2^bitLength − 1,
273+
// 11. If signedness is "signed" and x ≥ 2^(bitLength − 1),
274274
// then return x − 2^bitLength.
275-
if (signedness === 'signed' && x >= Math.pow(2, bitLength) - 1) {
275+
if (signedness === 'signed' && x >= Math.pow(2, bitLength - 1)) {
276276
return x - Math.pow(2, bitLength)
277277
}
278278

test/webidl/util.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,23 @@ test('webidl.util.ConvertToInt(V)', () => {
125125
}
126126

127127
assert.equal(ConvertToInt(111, 2, 'signed'), -1)
128+
129+
// https://webidl.spec.whatwg.org/#abstract-opdef-converttoint
130+
// For N-bit signed integers, lowerBound is -2^(N-1) and the modulo wrap
131+
// threshold (step 11) is 2^(N-1).
132+
assert.equal(ConvertToInt(128, 8, 'signed'), -128, '8-bit signed wrap at 128')
133+
assert.equal(ConvertToInt(200, 8, 'signed'), -56, '8-bit signed wrap at 200')
134+
assert.equal(
135+
ConvertToInt(-128, 8, 'signed', webidl.attributes.EnforceRange),
136+
-128,
137+
'8-bit signed EnforceRange lower bound'
138+
)
139+
assert.throws(() => {
140+
ConvertToInt(-129, 8, 'signed', webidl.attributes.EnforceRange)
141+
}, TypeError, '8-bit signed EnforceRange below lower bound throws')
142+
assert.equal(
143+
ConvertToInt(-(2 ** 31), 32, 'signed', webidl.attributes.EnforceRange),
144+
-(2 ** 31),
145+
'32-bit signed EnforceRange lower bound'
146+
)
128147
})

0 commit comments

Comments
 (0)