Skip to content

[JSC] Fix undefined behavior in double-to-int conversions#66220

Merged
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
sosukesuzuki:eng/JSC-Fix-UB-in-double-to-int-conversions
Jun 2, 2026
Merged

[JSC] Fix undefined behavior in double-to-int conversions#66220
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
sosukesuzuki:eng/JSC-Fix-UB-in-double-to-int-conversions

Conversation

@sosukesuzuki
Copy link
Copy Markdown
Contributor

@sosukesuzuki sosukesuzuki commented Jun 2, 2026

3825a1a

[JSC] Fix undefined behavior in double-to-int conversions
https://bugs.webkit.org/show_bug.cgi?id=316051

Reviewed by Yusuke Suzuki.

Several call sites convert unbounded, caller-controlled doubles to narrow
integer types with a plain cast, which is undefined behavior when the
truncated value is not representable ([conv.fpint]). With inputs reachable
from JS (e.g. parseInt("80000000", 16), (1.5).toExponential(Infinity),
String.fromCodePoint(-1), o[2 ** 32]), every conversion fixed here trips
UBSan's float-cast-overflow check.

This is not purely theoretical: in Bun, this UB caused user-observable
bugs, e.g. parseInt("80000000", 16) returning a negative int32.

Make the conversions defined via truncateDoubleToInt32() /
truncateDoubleToUint32() / clampTo<unsigned>(), or by range-checking the
double before narrowing. No behavior change on current WebKit toolchains.

Tests: JSTests/stress/get-by-val-double-subscript-out-of-uint32-range.js
       JSTests/stress/jsonp-large-array-index.js
       JSTests/stress/number-tostring-methods-out-of-range-arguments.js
       JSTests/stress/parseint-large-result-int32-boxing.js
       JSTests/stress/string-from-code-point-out-of-range.js

* JSTests/stress/get-by-val-double-subscript-out-of-uint32-range.js: Added.
(shouldBe):
(get put):
* JSTests/stress/jsonp-large-array-index.js: Added.
(shouldBe):
* JSTests/stress/number-tostring-methods-out-of-range-arguments.js: Added.
(shouldBe):
* JSTests/stress/parseint-large-result-int32-boxing.js: Added.
(shouldBe):
(parseIntNoRadix):
* JSTests/stress/string-from-code-point-out-of-range.js: Added.
(shouldBe):
* Source/JavaScriptCore/dfg/DFGOperations.cpp:
(JSC::DFG::parseIntResult):
* Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp:
(Inspector::JSInjectedScriptHost::weakMapEntries):
(Inspector::JSInjectedScriptHost::weakSetEntries):
(Inspector::JSInjectedScriptHost::iteratorEntries):
* Source/JavaScriptCore/runtime/JSCJSValue.h:
(JSC::JSValue::getUInt32 const):
* Source/JavaScriptCore/runtime/LiteralParser.cpp:
(JSC::requires):
* Source/JavaScriptCore/runtime/NumberPrototype.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/runtime/StringConstructor.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):

Canonical link: https://commits.webkit.org/314356@main

fc6e2a8

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 win
✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 🧪 win-tests
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe
🧪 ios-wk2-wpt ✅ 🧪 api-mac-debug ✅ 🛠 gtk3-libwebrtc
✅ 🛠 🧪 jsc-x86-64 ✅ 🧪 api-ios ✅ 🧪 mac-wk1 ✅ 🛠 gtk
✅ 🛠 🧪 jsc-debug-arm64 ✅ 🛠 ios-safer-cpp ✅ 🧪 mac-wk2 ✅ 🧪 gtk-wk2
✅ 🛠 vision ✅ 🧪 mac-AS-debug-wk2 ✅ 🧪 api-gtk
loading 🛠 🧪 merge ✅ 🛠 vision-sim ✅ 🧪 mac-wk2-stress ✅ 🛠 playstation
✅ 🧪 vision-wk2 ✅ 🧪 mac-intel-wk2 🛠 jsc-armv7
✅ 🛠 tv ✅ 🛠 mac-safer-cpp 🧪 jsc-armv7-tests
✅ 🛠 tv-sim ✅ 🧪 mac-site-isolation
✅ 🛠 watch
✅ 🛠 watch-sim

@sosukesuzuki sosukesuzuki requested review from a team, burg, dcrousso and patrickangle as code owners June 2, 2026 02:09
@sosukesuzuki sosukesuzuki self-assigned this Jun 2, 2026
@sosukesuzuki sosukesuzuki added the JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues. label Jun 2, 2026
@sosukesuzuki sosukesuzuki added the merge-queue Applied to send a pull request to merge-queue label Jun 2, 2026
https://bugs.webkit.org/show_bug.cgi?id=316051

Reviewed by Yusuke Suzuki.

Several call sites convert unbounded, caller-controlled doubles to narrow
integer types with a plain cast, which is undefined behavior when the
truncated value is not representable ([conv.fpint]). With inputs reachable
from JS (e.g. parseInt("80000000", 16), (1.5).toExponential(Infinity),
String.fromCodePoint(-1), o[2 ** 32]), every conversion fixed here trips
UBSan's float-cast-overflow check.

This is not purely theoretical: in Bun, this UB caused user-observable
bugs, e.g. parseInt("80000000", 16) returning a negative int32.

Make the conversions defined via truncateDoubleToInt32() /
truncateDoubleToUint32() / clampTo<unsigned>(), or by range-checking the
double before narrowing. No behavior change on current WebKit toolchains.

Tests: JSTests/stress/get-by-val-double-subscript-out-of-uint32-range.js
       JSTests/stress/jsonp-large-array-index.js
       JSTests/stress/number-tostring-methods-out-of-range-arguments.js
       JSTests/stress/parseint-large-result-int32-boxing.js
       JSTests/stress/string-from-code-point-out-of-range.js

* JSTests/stress/get-by-val-double-subscript-out-of-uint32-range.js: Added.
(shouldBe):
(get put):
* JSTests/stress/jsonp-large-array-index.js: Added.
(shouldBe):
* JSTests/stress/number-tostring-methods-out-of-range-arguments.js: Added.
(shouldBe):
* JSTests/stress/parseint-large-result-int32-boxing.js: Added.
(shouldBe):
(parseIntNoRadix):
* JSTests/stress/string-from-code-point-out-of-range.js: Added.
(shouldBe):
* Source/JavaScriptCore/dfg/DFGOperations.cpp:
(JSC::DFG::parseIntResult):
* Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp:
(Inspector::JSInjectedScriptHost::weakMapEntries):
(Inspector::JSInjectedScriptHost::weakSetEntries):
(Inspector::JSInjectedScriptHost::iteratorEntries):
* Source/JavaScriptCore/runtime/JSCJSValue.h:
(JSC::JSValue::getUInt32 const):
* Source/JavaScriptCore/runtime/LiteralParser.cpp:
(JSC::requires):
* Source/JavaScriptCore/runtime/NumberPrototype.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/runtime/StringConstructor.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):

Canonical link: https://commits.webkit.org/314356@main
@webkit-commit-queue webkit-commit-queue force-pushed the eng/JSC-Fix-UB-in-double-to-int-conversions branch from fc6e2a8 to 3825a1a Compare June 2, 2026 10:55
@webkit-commit-queue
Copy link
Copy Markdown
Collaborator

Committed 314356@main (3825a1a): https://commits.webkit.org/314356@main

Reviewed commits have been landed. Closing PR #66220 and removing active labels.

@webkit-commit-queue webkit-commit-queue merged commit 3825a1a into WebKit:main Jun 2, 2026
@webkit-commit-queue webkit-commit-queue removed the merge-queue Applied to send a pull request to merge-queue label Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants