Skip to content

feat(libc): implement feraiseexcept - #8903

Merged
oneandonlydean merged 5 commits into
boykopovar:mainfrom
UnhealthyKraken:feat/libc-feraiseexcept
Oct 26, 2026
Merged

oneandonlydean merged 5 commits into
boykopovar:mainfrom
UnhealthyKraken:feat/libc-feraiseexcept

Conversation

@UnhealthyKraken

@UnhealthyKraken UnhealthyKraken commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

Implement the missing feraiseexcept export (NIfFNcyeCTo) by accumulating requested flags in both x87 and MXCSR, preserving other state and errno, and delivering enabled x87 exceptions with fwait. All six defined exception bits are supported; unverified bits throw before changing state. This deliberately does not call _Feraise, whose errno and range/inexact behavior differs.

The signature is from the public SDK fenv.h. The public 3.20 table and symbol database corroborate the NID. For the six supported bits, behavior follows FreeBSD amd64 fenv.c; console equivalence and module/library versions remain unmeasured and are recorded in debt.

Unknown bits are explicitly rejected before changing state, unlike the FreeBSD reference, which does not mask or validate the requested bits. This rejection is an unsupported-path policy; PS5 behavior for those bits is unknown.

Tested

Windows x86-64, GCC15.2 Release, isolated checkout based on 1ff5c8ac5c3050d71360957c5ff1be38aaac7114. Regression first: seven new tests fail baseline's missing export while the existing floating-point test passes. With the same final executables and only the unpatched libc swapped, baseline is 1 pass/7 fail; candidate is 8/8 pass.

The main case checks 196608 flag/control combinations: all 64 requested and prior flag sets, independent x87/SSE flags, 16 rounding combinations and three x87 precision modes. It checks errno, other control/status/tag/pointer fields, rejected masks, differing exception masks, and thread isolation. Six separate cases check enabled x87 traps; Windows validates the saved unmasked cause as well as the exception code. A direct native x87 load of the smallest subnormal and the implementation both produce Windows 0xc0000090 on this host, so the denormal case accepts that code only when the saved active flag is DE, not invalid.

At the original submitted head 2d22f777, the full Windows libs build succeeded; validation was 9/9 pass, including all 354 patched libraries loading with zero failures. The expected NID is verified in patched shared libc, which supplies the interface for libSceLibcInternal under the existing provider convention. Loading verifies linkage only. No Linux/macOS or console execution by this contributor. The POSIX trap handler confirms SIGFPE but does not inspect its saved cause. No games run.

Conventions, whitespace and registration checks pass (1148 targets, none unregistered). Independent read-only review found no actionable defect and did not rerun tests. The overlap report's 14 base-conflicted shared-file warnings were reviewed manually: no competing export. #6044 reorganizes tests; #6879 changes host math callers rather than adding this export. The original overlap run had no compared-file conflict or duplicate export. The review-correction scan also has none; its 14 current base-conflicted shared-file warnings were inspected at their fetched heads and concern unrelated stack/runtime, formatting, environment, archive, directory and test-reorganization work. #6044 remains a test-directory migration consideration when rebased. The debt paragraph was relocated away from #8397/#8287 documentation changes.

Review correction: the thread test now sets its errno sentinel after the first host barrier and captures errno immediately after the export, before the second barrier. The floating-point isolation checks and distinct thread sentinels are retained; no runtime code changed. Filip722's Linux review reports 22/30 original runs passing, barrier-induced errno changes, and 30/30 passing with this test correction; those are attributed reviewer results, not execution on this Windows host.

Locally, a deterministic temporary probe makes both barriers set errno to 789: the original test fails and the repaired test passes against the same preserved DLL. A negative control that changes errno inside the called export still fails the repaired assertion. The rebuilt eight Windows tests pass, the main test passes 30 consecutive runs, and identical final executables pass 8/8 against both preserved baseline and candidate DLLs (byte-identical SHA256 bf4a81f2a272152f4886821d3c432b6ce14b98302037c5439a91297888ad8a75). These review checks rebuild the affected targets, not the entire library collection. Conventions and whitespace checks pass; independent read-only review found no actionable issue and did not rerun tests.

Checklist

  • Based on current main; no other open PR implements the same functions

  • One topic per PR; follow-ups go in a new PR

  • No comments in code except technical debt

  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file

  • No notes, investigation .md files or images added to the repository (attach them to this PR)

  • New third-party code is a submodule built from source

  • Generic behaviour, not specific to one title

  • Depends on: none

  • Fixes: none

  • Unblocks: none

  • GPUs tested: n/a

  • AI-assisted: yes

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Progress report (cceb6c3 → 676ee4f)

➖ System libraries: 50.06% (+0.0%, +1 implemented functions)

✅ 1 implemented
Library Name
libc feraiseexcept_nid_postfix

Changed libraries (implemented exports)

Library Before After Change
libc 1347/1357 (99.26%) 1348/1358 (99.26%) +0.00 pp

@MarcZX10

Copy link
Copy Markdown
Contributor

I ran an additional native Linux check on exact head 2d22f777eb with GCC 12.2. I compiled the PR’s FloatingPoint.cpp into a temporary shared object and its existing GuestRaiseExcept.cpp into a host harness, supplying only a temporary __error_nid_postfix stub for this isolated test. The normal state/errno/thread cases pass, and all six enabled-x87 trap invocations exit through the test’s SIGFPE handler. The PR conventions checker and git diff --check also pass. This validates the implementation on this Linux host; it does not validate the built AnyPS5 libc or inspect the POSIX trap cause.

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the new export and regression coverage. The implementation updates x87 and MXCSR flags independently, rejects unsupported bits before changing state, preserves errno/control fields, and uses fwait for enabled x87 exceptions. I independently ran the PR test on Linux with GCC 12.2 through a temporary host harness; the state, errno, thread, and six trap cases passed. Console behavior remains unmeasured and is clearly recorded in debt. The platform jobs still running are not covered by this approval.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

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.

Pull request Shared files not compared
PR 5021 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 5303 docs/dev/debt/libc.md
PR 6713 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 7081 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 7201 core/libs/prx/libc/CMakeLists.txt
PR 7386 docs/dev/debt/libc.md
PR 7447 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 7544 docs/dev/debt/libc.md
PR 7648 docs/dev/debt/libc.md
PR 7715 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 7851 core/libs/prx/libc/CMakeLists.txt
core/libs/prx/libc/include/Api.hpp
PR 8150 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 9371 docs/dev/debt/libc.md
PR 9447 docs/dev/debt/libc.md
PR 9526 docs/dev/debt/libc.md
PR 9775 core/libs/prx/libc/CMakeLists.txt
PR 9929 core/libs/prx/libc/CMakeLists.txt
docs/dev/debt/libc.md
PR 9953 docs/dev/debt/libc.md
PR 9964 docs/dev/debt/libc.md
PR 10002 docs/dev/debt/libc.md
PR 10007 docs/dev/debt/libc.md
PR 10158 docs/dev/debt/libc.md
PR 10200 docs/dev/debt/libc.md
PR 10234 docs/dev/debt/libc.md
PR 10315 docs/dev/debt/libc.md
PR 10317 docs/dev/debt/libc.md
PR 10321 docs/dev/debt/libc.md
PR 10325 docs/dev/debt/libc.md
PR 10328 docs/dev/debt/libc.md
PR 10345 docs/dev/debt/libc.md
PR 10349 docs/dev/debt/libc.md
PR 10405 docs/dev/debt/libc.md
PR 10467 docs/dev/debt/libc.md
PR 10506 docs/dev/debt/libc.md
PR 10510 docs/dev/debt/libc.md
PR 10512 docs/dev/debt/libc.md
PR 10529 docs/dev/debt/libc.md
PR 10565 docs/dev/debt/libc.md
PR 10749 core/libs/prx/libc/include/Api.hpp
docs/dev/debt/libc.md
PR 11332 docs/dev/debt/libc.md
PR 11341 docs/dev/debt/libc.md

@UnhealthyKraken UnhealthyKraken mentioned this pull request Oct 21, 2026
12 tasks done
@r1p0N

r1p0N commented Oct 21, 2026

Copy link
Copy Markdown

The implementation matches FreeBSD's amd64 feraiseexcept (fesetexceptflag on x87 status and MXCSR, then __fwait()), so valid masks behave the same way.
One difference worth stating in the debt entry: FreeBSD neither masks nor validates excepts, while this throws std::invalid_argument for bits outside the six exceptions. That is consistent with the throw-on-unknown rule and avoids writing reserved MXCSR bits, but it is a deliberate deviation from the console's likely behaviour, and the debt note should say so if it does not already.
Not run: the tests (they dlopen the built libc and need the full build).

@Filip722

Copy link
Copy Markdown
Contributor

Native Linux full-project validation on exact head 2d22f777eb4b4928df17f0aeeb211f61ae2d70f9 found an intermittent issue in the new test's Threads() errno assertion. The export itself preserved errno in the instrumented runs; the host barriers changed it outside the call.

Environment: Debian 13.7 x86-64, kernel 7.2.9-x64v3-xanmod1, Ryzen 5 7640HS, GCC/libstdc++ 15.2.0, CMake 3.31.6, Release, bundled dependencies, BUILD_TESTING=ON, ANYPS5_RELINKER_ONLY=OFF, two build jobs. Built the actual libc, guest_raise_except_tests, guest_floating_point_tests, and nid_patcher; no stubbed errno provider.

Repro / diagnosis:

  • The unmodified guest_raise_except executable passed 22/30 runs and aborted 8/30 with feraiseexcept: thread-local errno. The focused CTest run also reproduced it.
  • A temporary diagnostic copy read errno immediately before the export, immediately after it, and after the second ready.arrive_and_wait(). Failing examples were flag=4 before=104 after=104 afterBarrier=11 and flag=1 before=11 after=11 afterBarrier=11. Thus either host barrier can spoil the sentinel; the export preserves the value it receives. The real project's __error_nid_postfix() returns &errno; this libstdc++ uses futex waits in the barrier's atomic-wait path and allows EAGAIN (11) without restoring errno.
  • A minimal temporary correction passed 30/30 runs against the same built libc: set the sentinel after the first barrier and capture errno before the second, then assert the captured value. The existing floating-point environment checks can stay after the barrier:
ready.arrive_and_wait();
*__error_nid_postfix()=static_cast<int>(100+flag);
Require(raiseFlags(static_cast<int>(flag))==0,"thread return");
const int raisedError=*__error_nid_postfix();
ready.arrive_and_wait();
// Keep the existing environment checks here, then:
Require(raisedError==static_cast<int>(100+flag),"thread-local errno");

Additional passing evidence:

  • All six original enabled-x87 trap cases and the existing guest_floating_point control passed three consecutive runs each.
  • Extended a temporary copy of the existing POSIX test with sigaction(SA_SIGINFO) and checked SIGFPE plus uc_mcontext.fpregs->swd & ~uc_mcontext.fpregs->cwd & 0x3f against exactly the requested bit. All six bits, including denormal, passed three runs each. This checks the saved active cause in addition to signal delivery.
  • Ran the project's NID patcher on a temporary copy of the actual libc; nm -D --defined-only contains exactly one NIfFNcyeCTo export. This is packaging verification, not a full patched-runtime/title test.
  • Negative control: restored only FloatingPoint.cpp from merge-base 1ff5c8ac5c3050d71360957c5ff1be38aaac7114 and rebuilt libc, retaining the final test executables. The seven new cases failed with the missing-export assertion; the existing floating-point case passed. After restoring the exact PR implementation, the six trap cases and old control passed again, while the original main case reproduced the barrier/errno failure. The corrected temporary test and saved-cause checks passed against the restored library.

Build/repro commands:

CCACHE_DIR=/tmp/anyps5-ccache cmake --build build --target libc guest_raise_except_tests guest_floating_point_tests nid_patcher --parallel 2
ctest --test-dir build --output-on-failure --parallel 2 --repeat until-fail:3 -R '^(guest_raise_except(_trap_[0-5])?|guest_floating_point)$'

All diagnostic variants stayed under /tmp; repository sources are restored to the exact head. No Windows, console or game execution in this check. AI-assisted testing/reporting: yes.

@UnhealthyKraken

Copy link
Copy Markdown
Contributor Author

Addressed both review points in 35c508e.

The thread test now sets its distinct errno sentinel after barrier one and captures it immediately after feraiseexcept, before barrier two. The floating-point checks remain unchanged. A deterministic barrier-side errno injection fails the old test and passes the repaired test using the same DLL; an export-side errno mutation still fails the repaired assertion. On Windows, all eight relevant tests pass, the main test passes 30 consecutive runs, and identical final executables pass 8/8 against both preserved and candidate DLLs. The DLLs are byte-identical; no runtime code changed. Filip722's Linux results remain attributed reviewer evidence; I have not run Linux here.

The debt entry now explicitly states that FreeBSD does not mask or validate the requested exception bits, whereas this implementation rejects unknown bits before modifying state. Console behavior for those bits remains unknown. Conventions and whitespace checks pass. The PR description separates the original full-library validation from these focused review checks.

@oneandonlydean oneandonlydean self-assigned this Oct 23, 2026
danielradosa added a commit to danielradosa/AnyPS5 that referenced this pull request Oct 24, 2026
@edubox edubox mentioned this pull request Oct 24, 2026
12 tasks done
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 25, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

@UnhealthyKraken #10688 landed and conflicted with this in docs/dev/debt/libc.md, so I merged main into the branch (676ee4f). The only conflict was the two neighbouring debt bullets, and both are kept; no code changed. Next is CI on this head.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 25, 2026
@UnhealthyKraken

Copy link
Copy Markdown
Contributor Author

@oneandonlydean Recorded your history-preserving main merge 676ee4fe427ff683637d5725bce6b4acf2c18be3, including both neighboring debt entries. The applicable hosted checks on this head have now completed successfully; full product Linux/Windows jobs are skipped. No additional source change is needed for the conflict you resolved, and I have not rewritten your merge or claimed a new runtime run. No local builds/tests. AI-assisted: yes.

@oneandonlydean
oneandonlydean merged commit c74530e into boykopovar:main Oct 26, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants