From fba96d6422ce802aa2a79f72e3a5fd947dcb52a2 Mon Sep 17 00:00:00 2001 From: Alex <270190108+CouchRiv@users.noreply.github.com> Date: Sun, 11 Oct 2026 10:07:47 -0400 Subject: [PATCH] fix(libc): asin(|x| > 1) returns the x86 default NaN and leaves errno unchanged On main asin(2.0) returns 0x7ff8000000000000 and sets errno to 33; FreeBSD msun (lib/msun/src/e_asin.c) returns 0xfff8000000000000 and never sets errno. asin now handles |x| > 1 itself with quiet comparisons, so a NaN input still raises no exception. For |x| <= 1 and for NaN the host function is still called. Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- core/libs/prx/libc/src/Math.cpp | 8 +++++++- core/libs/tests/GuestMath.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/core/libs/prx/libc/src/Math.cpp b/core/libs/prx/libc/src/Math.cpp index 9d6a8aebd..aef6c0385 100644 --- a/core/libs/prx/libc/src/Math.cpp +++ b/core/libs/prx/libc/src/Math.cpp @@ -70,7 +70,13 @@ int APS5_VABI __isnormalf_nid_postfix(float x) { return std::isnormal(x) ? 1 : 0 int APS5_VABI __isinff_nid_postfix(float x) { return std::isinf(x) ? 1 : 0; } double APS5_VABI cbrt_nid_postfix(double x) { return std::cbrt(x); } -double APS5_VABI asin_nid_postfix(double x) { return std::asin(x); } +double APS5_VABI asin_nid_postfix(double x) { + if (std::isgreater(x, 1.0) || std::isless(x, -1.0)) { + std::feraiseexcept(FE_INVALID); + return -std::numeric_limits::quiet_NaN(); + } + return std::asin(x); +} double APS5_VABI acos_nid_postfix(double x) { return std::acos(x); } double APS5_VABI sqrt_nid_postfix(double x) { return std::sqrt(x); } float APS5_VABI sqrtf_nid_postfix(float x) { return std::sqrt(x); } diff --git a/core/libs/tests/GuestMath.cpp b/core/libs/tests/GuestMath.cpp index 6d56671b5..2179dd60a 100644 --- a/core/libs/tests/GuestMath.cpp +++ b/core/libs/tests/GuestMath.cpp @@ -40,6 +40,7 @@ int APS5_VABI __fpclassifyf_nid_postfix(float); float APS5_VABI fmodf_nid_postfix(float, float); float APS5_VABI asinf_nid_postfix(float); float APS5_VABI acosf_nid_postfix(float); +double APS5_VABI asin_nid_postfix(double); float APS5_VABI atan2f_nid_postfix(float, float); float APS5_VABI hypotf_nid_postfix(float, float); double APS5_VABI hypot_nid_postfix(double, double); @@ -281,6 +282,36 @@ static void CheckIntegerConversions() { static bool Near(double value, double expected, double tolerance) { return std::abs(value - expected) <= tolerance * std::abs(expected); } +static void CheckAsin() { + const double pi = 3.14159265358979323846; + const double pi_2 = pi / 2; + const double nan = std::numeric_limits::quiet_NaN(); + const double infinity = std::numeric_limits::infinity(); + + Require(asin_nid_postfix(0.) == 0.); + Require(std::signbit(asin_nid_postfix(-0.))); + Require(Near(asin_nid_postfix(1.), pi_2, 1e-15)); + Require(Near(asin_nid_postfix(-1.), -pi_2, 1e-15)); + Require(std::isnan(asin_nid_postfix(2.0)) && std::signbit(asin_nid_postfix(2.0))); + Require(std::isnan(asin_nid_postfix(-2.0)) && std::signbit(asin_nid_postfix(-2.0))); + Require(std::isnan(asin_nid_postfix(infinity)) && std::signbit(asin_nid_postfix(infinity))); + Require(std::isnan(asin_nid_postfix(-infinity)) && std::signbit(asin_nid_postfix(-infinity))); + Require(std::isnan(asin_nid_postfix(nan))); + Require(Near(asin_nid_postfix(0.5), pi/6, 1e-15)); + Require(Near(asin_nid_postfix(-0.5), -pi/6, 1e-15)); + Require(Near(asin_nid_postfix(1./std::sqrt(2)), pi/4, 1e-15)); + Require(asin_nid_postfix(1e-300) == 1e-300); + Require(asin_nid_postfix(-1e-300) == -1e-300); + std::feclearexcept(FE_ALL_EXCEPT); + errno = 0; + asin_nid_postfix(2.0); + Require(std::fetestexcept(FE_INVALID)); + Require(errno == 0); + std::feclearexcept(FE_ALL_EXCEPT); + asin_nid_postfix(nan); + Require(!std::fetestexcept(FE_INVALID)); +} + static void CheckHyperbolic() { const double infinity = std::numeric_limits::infinity(); Require(sinh_nid_postfix(0.) == 0. && std::signbit(sinh_nid_postfix(-0.))); @@ -478,6 +509,7 @@ int main() { Require(__isnormalf_nid_postfix(std::numeric_limits::denorm_min()) == 0); Require(__isnormal_nid_postfix(1.) == 1 && __isnormal_nid_postfix(0.) == 0); Require(__isnormal_nid_postfix(std::numeric_limits::denorm_min()) == 0); + CheckAsin(); const auto quotient = div_nid_postfix(7, 2); Require(quotient.quot == 3 && quotient.rem == 1); const auto negativeNumerator = div_nid_postfix(-7, 2);