Repository navigation
fix(libc): leave errno unchanged from scalbn and scalbnf on every host - #12681
Conversation
The titles' scalbn and scalbnf never set errno, at any exponent. On Windows the host scalbn already matches, but glibc's scalbn and scalbnf set ERANGE on overflow and on underflow to zero (found by rooklz while reviewing boykopovar#12676), so on Linux they did. Both now keep errno across the host call, as scalbln and scalblnf already do. CheckScalbnErrno checks results read from the titles' libc.prx. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rooklz
left a comment
There was a problem hiding this comment.
Approving. Your Not-tested section said Linux and macOS weren't run, so I ran both at a561f4e.
Setup. A standalone build of the head scalbn_nid_postfix/scalbnf_nid_postfix bodies and the verbatim CheckScalbnErrno (GuestMath.cpp L656–686). I also built main's one-liners as the control. Each arm also ran a 1,000,000-pair xorshift sweep (random double/float bits, exponents in ±2100 / ±400). The sweep compared values against bare std::scalbn and counted errno changes with errno preset to 7.
| host | arm | CheckScalbnErrno failures |
sweep errno changes |
sweep value diffs |
|---|---|---|---|---|
| Ubuntu 24.04 x86_64, glibc 2.39, GCC 13 | head | 0 | 0 | 0 |
| same | main |
7 (errno=34) |
1,124,062 | 0 |
| macOS arm64, Apple clang | head | 0 | 0 | 0 |
| same | main |
0 | 0 | 0 |
So you get the Linux negative control you couldn't get on Windows: the new test is RED on glibc with main's Math.cpp, and green with this PR.
Mutants (glibc):
- Drop the restore in
scalbnonly: 3 rows fail. - Drop the restore in
scalbnfonly: 4 rows fail.
Both are killed, so each function is covered on its own.
Other checks:
- The PR is based on
3a2b919816.git merge-treeis clean againstmainand pairwise against #12676. check_conventions --base upstream/mainpasses.- The save/restore matches the existing
fmodandexp2pattern in the same file.
Note for a later PR (not blocking): glibc's scalbnl sets ERANGE too. std::scalbn(1.0L, ±20000) gives errno=34, so scalbnl still differs on Linux. Leaving it out until the titles' long-double behaviour is measured is the right call, per the rules.
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
Windows run of this head
AI-assisted: yes (Claude Code) |
|
Checked the errno save/restore around |
What
scalbnandscalbnfnow leaveerrnounchanged on every host, as thelibc.prxthat titles ship does.Both call the host
std::scalbn. On Windows that never setserrno. glibc'sscalbnandscalbnfsetERANGEon overflow and on underflow to zero, as rooklz found while reviewing #12676. So on Linux both functions changederrnowhere the titles don't. They now save and restoreerrnoaround the host call, asscalbln,scalblnfandscalblnlalready do withErrnoGuardinMathExact.cpp, and asfmoddoes.What the titles do, read natively from PPSA07923's
libc.prx(a scratch loader calls its functions by NID), witherrnopreset to 7:errnoscalbn(1, 2000)infscalbn(1, -2000),scalbn(1, -1075)0scalbn(1, -1074)0x1p-1074scalbnf(1, 200),scalbnf(1, 2000)infscalbnf(1, -200),scalbnf(1, -2000)0scalbln/scalblnfat the same and at ±(2^47 − 1)ldexp(1, 2000),ldexp(1, -2000),ldexp(1, -1075), for contrastinf,0,0ERANGEldexp(double) keeps settingERANGEas before, which matches the titles.scalbnlis unchanged: I haven't measured the titles' long double behaviour.Tested
Windows 11, WinLibs GCC 15.2.0 UCRT r7, Release,
main3a2b919816.(x, n)pairs,scalbnandscalbnfmatch the titles'libc.prxon every value anderrno, on PPSA07923 and PPSA05916, both onmainand with this PR.guest_mathgainsCheckScalbnErrno: 10 rows from the table above. Each must give the titles' bits and leaveerrnounchanged.scalbndoesn't seterrno, so the test passes on Windows withmain'sMath.cpptoo. The failure it guards against is on glibc. rooklz's standalone run of the same pattern forldexpf(fix(libc): leave errno unchanged from ldexpf, as titles' libc.prx does #12676) showederrno = 34there, but I haven't run this test on Linux.guest_math,guest_math_exact,guest_dinkumware_internalsandpublic_headerspass 3/3. Conventions pass.tools/pr_overlap.py: 52 open PRs share a file. Two conflict inGuestMath.cppat the list of checks inmain()(line 2434), both mine: fix(libc): compute erff and erfcf with fdlibm's algorithm, as titles' libc.prx does #10226 and fix(libc): compute atan and atan2 with FreeBSD msun's algorithm, as titles' libc.prx does #10229. Each adds its own check call nearby, so whichever lands second needs a trivial rebase. Six more already conflict withmainand couldn't be compared (feat(libc): export _FDsign/_Dsign like MSVC CRT (PPSA34015) #6085, feat(libc): implement the nextafter and nexttoward families #6295, feat(libc): implement fesetenv #8937, fix(libc): compute asin and acos with FreeBSD msun's algorithm, as titles' libc.prx does #10253, fix(libc): set EDOM in fmod and fmodf where titles' libc.prx does #10345, fix(libc): set ERANGE for decimal subnormals in wcstod as strtod does #11892); none of their diffs touchesscalbnorscalbnf.Not tested: a Linux or macOS build or run.
Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code