diff --git a/Lib/test/test_free_threading/test_cmath.py b/Lib/test/test_free_threading/test_cmath.py new file mode 100644 index 00000000000000..4de3933330f683 --- /dev/null +++ b/Lib/test/test_free_threading/test_cmath.py @@ -0,0 +1,47 @@ +import cmath +import unittest + +from test.support import import_helper, threading_helper +from test.support.threading_helper import run_concurrently + +_interpreters = import_helper.import_module("_interpreters") + + +NTHREAD = 10 +SUBINTERPRETER_CODE = """ +import cmath +z = complex(float('inf'), float('inf')) +result = cmath.acos(z) +""" + + +@threading_helper.requires_working_threading() +class TestCmathSubinterpreterRace(unittest.TestCase): + def test_subinterpreter_init_race(self): + """Trigger race: subinterpreters init while threads use cmath""" + + def worker(): + self.use_cmath() + self.create_subinterpreter() + + run_concurrently(worker, nthreads=NTHREAD) + + def use_cmath(self): + """Use cmath functions to triggers special value lookups""" + c = complex(1.0, 2.0) + c_special = complex(float("inf"), 0) + for _ in range(100): + cmath.sqrt(c) + self.assertEqual(cmath.acos(c_special), complex(0, float("-inf"))) + + def create_subinterpreter(self): + """Create subinterpreter and import cmath""" + interp = _interpreters.create() + try: + _interpreters.exec(interp, SUBINTERPRETER_CODE) + finally: + _interpreters.destroy(interp) + + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-01-10-03-08.gh-issue-116738.972YsG.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-01-10-03-08.gh-issue-116738.972YsG.rst new file mode 100644 index 00000000000000..d6d9d02b017473 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-01-10-03-08.gh-issue-116738.972YsG.rst @@ -0,0 +1,2 @@ +Fix :mod:`cmath` data race when initializing trigonometric tables with +subinterpreters. diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index aee3e4f343d8be..659809df0ed22e 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -12,6 +12,8 @@ /* we need DBL_MAX, DBL_MIN, DBL_EPSILON, DBL_MANT_DIG and FLT_RADIX from float.h. We assume that FLT_RADIX is either 2 or 16. */ #include +#include +#include /* For _Py_log1p with workarounds for buggy handling of zeros. */ #include "_math.h" @@ -163,8 +165,15 @@ special_type(double d) raised. */ -static Py_complex acos_special_values[7][7]; - +static Py_complex acos_special_values[7][7] = { + { {P34,INF}, {P,INF}, {P,INF}, {P,-INF}, {P,-INF}, {P34,-INF}, {N,INF} }, + { {P12,INF}, {U,U}, {U,U}, {U,U}, {U,U}, {P12,-INF}, {N,N} }, + { {P12,INF}, {U,U}, {P12,0.}, {P12,-0.}, {U,U}, {P12,-INF}, {P12,N} }, + { {P12,INF}, {U,U}, {P12,0.}, {P12,-0.}, {U,U}, {P12,-INF}, {P12,N} }, + { {P12,INF}, {U,U}, {U,U}, {U,U}, {U,U}, {P12,-INF}, {N,N} }, + { {P14,INF}, {0.,INF}, {0.,INF}, {0.,-INF}, {0.,-INF}, {P14,-INF}, {N,INF} }, + { {N,INF}, {N,N}, {N,N}, {N,N}, {N,N}, {N,-INF}, {N,N} } +}; /*[clinic input] cmath.acos -> Py_complex_protected @@ -202,7 +211,15 @@ cmath_acos_impl(PyObject *module, Py_complex z) } -static Py_complex acosh_special_values[7][7]; +static Py_complex acosh_special_values[7][7] = { + { {INF,-P34}, {INF,-P}, {INF,-P}, {INF,P}, {INF,P}, {INF,P34}, {INF,N} }, + { {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {0.,-P12}, {0.,P12}, {U,U}, {INF,P12}, {N,P12} }, + { {INF,-P12}, {U,U}, {0.,-P12}, {0.,P12}, {U,U}, {INF,P12}, {N,P12} }, + { {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P14}, {INF,-0.}, {INF,-0.}, {INF,0.}, {INF,0.}, {INF,P14}, {INF,N} }, + { {INF,N}, {N,N}, {N,N}, {N,N}, {N,N}, {INF,N}, {N,N} } +}; /*[clinic input] cmath.acosh = cmath.acos @@ -257,7 +274,15 @@ cmath_asin_impl(PyObject *module, Py_complex z) } -static Py_complex asinh_special_values[7][7]; +static Py_complex asinh_special_values[7][7] = { + { {-INF,-P14}, {-INF,-0.}, {-INF,-0.}, {-INF,0.}, {-INF,0.}, {-INF,P14}, {-INF,N} }, + { {-INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {-INF,P12}, {N,N} }, + { {-INF,-P12}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {-INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P14}, {INF,-0.}, {INF,-0.}, {INF,0.}, {INF,0.}, {INF,P14}, {INF,N} }, + { {INF,N}, {N,N}, {N,-0.}, {N,0.}, {N,N}, {INF,N}, {N,N} } +}; /*[clinic input] cmath.asinh = cmath.acos @@ -318,7 +343,15 @@ cmath_atan_impl(PyObject *module, Py_complex z) } -static Py_complex atanh_special_values[7][7]; +static Py_complex atanh_special_values[7][7] = { + { {-0.,-P12}, {-0.,-P12}, {-0.,-P12}, {-0.,P12}, {-0.,P12}, {-0.,P12}, {-0.,N} }, + { {-0.,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {-0.,P12}, {N,N} }, + { {-0.,-P12}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {-0.,P12}, {-0.,N} }, + { {0.,-P12}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.,P12}, {0.,N} }, + { {0.,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {0.,P12}, {N,N} }, + { {0.,-P12}, {0.,-P12}, {0.,-P12}, {0.,P12}, {0.,P12}, {0.,P12}, {0.,N} }, + { {0.,-P12}, {N,N}, {N,N}, {N,N}, {N,N}, {0.,P12}, {N,N} } +}; /*[clinic input] cmath.atanh = cmath.acos @@ -391,7 +424,15 @@ cmath_cos_impl(PyObject *module, Py_complex z) /* cosh(infinity + i*y) needs to be dealt with specially */ -static Py_complex cosh_special_values[7][7]; +static Py_complex cosh_special_values[7][7] = { + { {INF,N}, {U,U}, {INF,0.}, {INF,-0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {N,0.}, {U,U}, {1.,0.}, {1.,-0.}, {U,U}, {N,0.}, {N,0.} }, + { {N,0.}, {U,U}, {1.,-0.}, {1.,0.}, {U,U}, {N,0.}, {N,0.} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {INF,N}, {U,U}, {INF,-0.}, {INF,0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {N,N}, {N,0.}, {N,0.}, {N,N}, {N,N}, {N,N} } +}; /*[clinic input] cmath.cosh = cmath.acos @@ -453,7 +494,15 @@ cmath_cosh_impl(PyObject *module, Py_complex z) /* exp(infinity + i*y) and exp(-infinity + i*y) need special treatment for finite y */ -static Py_complex exp_special_values[7][7]; +static Py_complex exp_special_values[7][7] = { + { {0.,0.}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.,0.}, {0.,0.} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {N,N}, {U,U}, {1.,-0.}, {1.,0.}, {U,U}, {N,N}, {N,N} }, + { {N,N}, {U,U}, {1.,-0.}, {1.,0.}, {U,U}, {N,N}, {N,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {INF,N}, {U,U}, {INF,-0.}, {INF,0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {N,N}, {N,-0.}, {N,0.}, {N,N}, {N,N}, {N,N} } +}; /*[clinic input] cmath.exp = cmath.acos @@ -512,7 +561,15 @@ cmath_exp_impl(PyObject *module, Py_complex z) return r; } -static Py_complex log_special_values[7][7]; +static Py_complex log_special_values[7][7] = { + { {INF,-P34}, {INF,-P}, {INF,-P}, {INF,P}, {INF,P}, {INF,P34}, {INF,N} }, + { {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {-INF,-P}, {-INF,P}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {-INF,-0.}, {-INF,0.}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P12}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,P12}, {N,N} }, + { {INF,-P14}, {INF,-0.}, {INF,-0.}, {INF,0.}, {INF,0.}, {INF,P14}, {INF,N} }, + { {INF,N}, {N,N}, {N,N}, {N,N}, {N,N}, {INF,N}, {N,N} } +}; static Py_complex c_log(Py_complex z) @@ -628,7 +685,15 @@ cmath_sin_impl(PyObject *module, Py_complex z) /* sinh(infinity + i*y) needs to be dealt with specially */ -static Py_complex sinh_special_values[7][7]; +static Py_complex sinh_special_values[7][7] = { + { {INF,N}, {U,U}, {-INF,-0.}, {-INF,0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {0.,N}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {0.,N}, {0.,N} }, + { {0.,N}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.,N}, {0.,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {INF,N}, {U,U}, {INF,-0.}, {INF,0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {N,N}, {N,-0.}, {N,0.}, {N,N}, {N,N}, {N,N} } +}; /*[clinic input] cmath.sinh = cmath.acos @@ -687,7 +752,15 @@ cmath_sinh_impl(PyObject *module, Py_complex z) } -static Py_complex sqrt_special_values[7][7]; +static Py_complex sqrt_special_values[7][7] = { + { {INF,-INF}, {0.,-INF}, {0.,-INF}, {0.,INF}, {0.,INF}, {INF,INF}, {N,INF} }, + { {INF,-INF}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,INF}, {N,N} }, + { {INF,-INF}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {INF,INF}, {N,N} }, + { {INF,-INF}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {INF,INF}, {N,N} }, + { {INF,-INF}, {U,U}, {U,U}, {U,U}, {U,U}, {INF,INF}, {N,N} }, + { {INF,-INF}, {INF,-0.}, {INF,-0.}, {INF,0.}, {INF,0.}, {INF,INF}, {INF,N} }, + { {INF,-INF}, {N,N}, {N,N}, {N,N}, {N,N}, {INF,INF}, {N,N} } +}; /*[clinic input] cmath.sqrt = cmath.acos @@ -786,7 +859,15 @@ cmath_tan_impl(PyObject *module, Py_complex z) /* tanh(infinity + i*y) needs to be dealt with specially */ -static Py_complex tanh_special_values[7][7]; +static Py_complex tanh_special_values[7][7] = { + { {-1.,0.}, {U,U}, {-1.,-0.}, {-1.,0.}, {U,U}, {-1.,0.}, {-1.,0.} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {-0.0,N}, {U,U}, {-0.,-0.}, {-0.,0.}, {U,U}, {-0.0,N}, {-0.,N} }, + { {0.0,N}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.0,N}, {0.,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {1.,0.}, {U,U}, {1.,-0.}, {1.,0.}, {U,U}, {1.,0.}, {1.,0.} }, + { {N,N}, {N,N}, {N,-0.}, {N,0.}, {N,N}, {N,N}, {N,N} } +}; /*[clinic input] cmath.tanh = cmath.acos @@ -969,7 +1050,15 @@ cmath_polar_impl(PyObject *module, Py_complex z) */ -static Py_complex rect_special_values[7][7]; +static Py_complex rect_special_values[7][7] = { + { {INF,N}, {U,U}, {-INF,0.}, {-INF,-0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {0.,0.}, {U,U}, {-0.,0.}, {-0.,-0.}, {U,U}, {0.,0.}, {0.,0.} }, + { {0.,0.}, {U,U}, {0.,-0.}, {0.,0.}, {U,U}, {0.,0.}, {0.,0.} }, + { {N,N}, {U,U}, {U,U}, {U,U}, {U,U}, {N,N}, {N,N} }, + { {INF,N}, {U,U}, {INF,-0.}, {INF,0.}, {U,U}, {INF,N}, {INF,N} }, + { {N,N}, {N,N}, {N,0.}, {N,0.}, {N,N}, {N,N}, {N,N} } +}; /*[clinic input] cmath.rect @@ -1173,6 +1262,8 @@ static PyMethodDef cmath_methods[] = { {NULL, NULL} /* sentinel */ }; +static int verify_special_value_tables(void); + static int cmath_exec(PyObject *mod) { @@ -1202,12 +1293,30 @@ cmath_exec(PyObject *mod) return -1; } - /* initialize special value tables */ + verify_special_value_tables(); + + return 0; +} + +static int +verify_special_value_tables(void) +{ + Py_complex acos_special_values_l[7][7]; + Py_complex acosh_special_values_l[7][7]; + Py_complex asinh_special_values_l[7][7]; + Py_complex atanh_special_values_l[7][7]; + Py_complex cosh_special_values_l[7][7]; + Py_complex exp_special_values_l[7][7]; + Py_complex log_special_values_l[7][7]; + Py_complex sinh_special_values_l[7][7]; + Py_complex sqrt_special_values_l[7][7]; + Py_complex tanh_special_values_l[7][7]; + Py_complex rect_special_values_l[7][7]; #define INIT_SPECIAL_VALUES(NAME, BODY) { Py_complex* p = (Py_complex*)NAME; BODY } #define C(REAL, IMAG) p->real = REAL; p->imag = IMAG; ++p; - INIT_SPECIAL_VALUES(acos_special_values, { + INIT_SPECIAL_VALUES(acos_special_values_l, { C(P34,INF) C(P,INF) C(P,INF) C(P,-INF) C(P,-INF) C(P34,-INF) C(N,INF) C(P12,INF) C(U,U) C(U,U) C(U,U) C(U,U) C(P12,-INF) C(N,N) C(P12,INF) C(U,U) C(P12,0.) C(P12,-0.) C(U,U) C(P12,-INF) C(P12,N) @@ -1217,7 +1326,7 @@ cmath_exec(PyObject *mod) C(N,INF) C(N,N) C(N,N) C(N,N) C(N,N) C(N,-INF) C(N,N) }) - INIT_SPECIAL_VALUES(acosh_special_values, { + INIT_SPECIAL_VALUES(acosh_special_values_l, { C(INF,-P34) C(INF,-P) C(INF,-P) C(INF,P) C(INF,P) C(INF,P34) C(INF,N) C(INF,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(INF,P12) C(N,N) C(INF,-P12) C(U,U) C(0.,-P12) C(0.,P12) C(U,U) C(INF,P12) C(N,P12) @@ -1227,7 +1336,7 @@ cmath_exec(PyObject *mod) C(INF,N) C(N,N) C(N,N) C(N,N) C(N,N) C(INF,N) C(N,N) }) - INIT_SPECIAL_VALUES(asinh_special_values, { + INIT_SPECIAL_VALUES(asinh_special_values_l, { C(-INF,-P14) C(-INF,-0.) C(-INF,-0.) C(-INF,0.) C(-INF,0.) C(-INF,P14) C(-INF,N) C(-INF,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(-INF,P12) C(N,N) C(-INF,-P12) C(U,U) C(-0.,-0.) C(-0.,0.) C(U,U) C(-INF,P12) C(N,N) @@ -1237,7 +1346,7 @@ cmath_exec(PyObject *mod) C(INF,N) C(N,N) C(N,-0.) C(N,0.) C(N,N) C(INF,N) C(N,N) }) - INIT_SPECIAL_VALUES(atanh_special_values, { + INIT_SPECIAL_VALUES(atanh_special_values_l, { C(-0.,-P12) C(-0.,-P12) C(-0.,-P12) C(-0.,P12) C(-0.,P12) C(-0.,P12) C(-0.,N) C(-0.,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(-0.,P12) C(N,N) C(-0.,-P12) C(U,U) C(-0.,-0.) C(-0.,0.) C(U,U) C(-0.,P12) C(-0.,N) @@ -1247,7 +1356,7 @@ cmath_exec(PyObject *mod) C(0.,-P12) C(N,N) C(N,N) C(N,N) C(N,N) C(0.,P12) C(N,N) }) - INIT_SPECIAL_VALUES(cosh_special_values, { + INIT_SPECIAL_VALUES(cosh_special_values_l, { C(INF,N) C(U,U) C(INF,0.) C(INF,-0.) C(U,U) C(INF,N) C(INF,N) C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) C(N,0.) C(U,U) C(1.,0.) C(1.,-0.) C(U,U) C(N,0.) C(N,0.) @@ -1257,7 +1366,7 @@ cmath_exec(PyObject *mod) C(N,N) C(N,N) C(N,0.) C(N,0.) C(N,N) C(N,N) C(N,N) }) - INIT_SPECIAL_VALUES(exp_special_values, { + INIT_SPECIAL_VALUES(exp_special_values_l, { C(0.,0.) C(U,U) C(0.,-0.) C(0.,0.) C(U,U) C(0.,0.) C(0.,0.) C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) C(N,N) C(U,U) C(1.,-0.) C(1.,0.) C(U,U) C(N,N) C(N,N) @@ -1267,7 +1376,7 @@ cmath_exec(PyObject *mod) C(N,N) C(N,N) C(N,-0.) C(N,0.) C(N,N) C(N,N) C(N,N) }) - INIT_SPECIAL_VALUES(log_special_values, { + INIT_SPECIAL_VALUES(log_special_values_l, { C(INF,-P34) C(INF,-P) C(INF,-P) C(INF,P) C(INF,P) C(INF,P34) C(INF,N) C(INF,-P12) C(U,U) C(U,U) C(U,U) C(U,U) C(INF,P12) C(N,N) C(INF,-P12) C(U,U) C(-INF,-P) C(-INF,P) C(U,U) C(INF,P12) C(N,N) @@ -1277,7 +1386,7 @@ cmath_exec(PyObject *mod) C(INF,N) C(N,N) C(N,N) C(N,N) C(N,N) C(INF,N) C(N,N) }) - INIT_SPECIAL_VALUES(sinh_special_values, { + INIT_SPECIAL_VALUES(sinh_special_values_l, { C(INF,N) C(U,U) C(-INF,-0.) C(-INF,0.) C(U,U) C(INF,N) C(INF,N) C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) C(0.,N) C(U,U) C(-0.,-0.) C(-0.,0.) C(U,U) C(0.,N) C(0.,N) @@ -1287,7 +1396,7 @@ cmath_exec(PyObject *mod) C(N,N) C(N,N) C(N,-0.) C(N,0.) C(N,N) C(N,N) C(N,N) }) - INIT_SPECIAL_VALUES(sqrt_special_values, { + INIT_SPECIAL_VALUES(sqrt_special_values_l, { C(INF,-INF) C(0.,-INF) C(0.,-INF) C(0.,INF) C(0.,INF) C(INF,INF) C(N,INF) C(INF,-INF) C(U,U) C(U,U) C(U,U) C(U,U) C(INF,INF) C(N,N) C(INF,-INF) C(U,U) C(0.,-0.) C(0.,0.) C(U,U) C(INF,INF) C(N,N) @@ -1297,7 +1406,7 @@ cmath_exec(PyObject *mod) C(INF,-INF) C(N,N) C(N,N) C(N,N) C(N,N) C(INF,INF) C(N,N) }) - INIT_SPECIAL_VALUES(tanh_special_values, { + INIT_SPECIAL_VALUES(tanh_special_values_l, { C(-1.,0.) C(U,U) C(-1.,-0.) C(-1.,0.) C(U,U) C(-1.,0.) C(-1.,0.) C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) C(-0.0,N) C(U,U) C(-0.,-0.) C(-0.,0.) C(U,U) C(-0.0,N) C(-0.,N) @@ -1307,7 +1416,7 @@ cmath_exec(PyObject *mod) C(N,N) C(N,N) C(N,-0.) C(N,0.) C(N,N) C(N,N) C(N,N) }) - INIT_SPECIAL_VALUES(rect_special_values, { + INIT_SPECIAL_VALUES(rect_special_values_l, { C(INF,N) C(U,U) C(-INF,0.) C(-INF,-0.) C(U,U) C(INF,N) C(INF,N) C(N,N) C(U,U) C(U,U) C(U,U) C(U,U) C(N,N) C(N,N) C(0.,0.) C(U,U) C(-0.,0.) C(-0.,-0.) C(U,U) C(0.,0.) C(0.,0.) @@ -1316,6 +1425,32 @@ cmath_exec(PyObject *mod) C(INF,N) C(U,U) C(INF,-0.) C(INF,0.) C(U,U) C(INF,N) C(INF,N) C(N,N) C(N,N) C(N,0.) C(N,0.) C(N,N) C(N,N) C(N,N) }) + + static_assert(sizeof(acos_special_values_l) == sizeof(acos_special_values), "acos table size mismatch"); + static_assert(sizeof(acosh_special_values_l) == sizeof(acosh_special_values), "acosh table size mismatch"); + static_assert(sizeof(asinh_special_values_l) == sizeof(asinh_special_values), "asinh table size mismatch"); + static_assert(sizeof(atanh_special_values_l) == sizeof(atanh_special_values), "atanh table size mismatch"); + static_assert(sizeof(cosh_special_values_l) == sizeof(cosh_special_values), "cosh table size mismatch"); + static_assert(sizeof(exp_special_values_l) == sizeof(exp_special_values), "exp table size mismatch"); + static_assert(sizeof(log_special_values_l) == sizeof(log_special_values), "log table size mismatch"); + static_assert(sizeof(sinh_special_values_l) == sizeof(sinh_special_values), "sinh table size mismatch"); + static_assert(sizeof(sqrt_special_values_l) == sizeof(sqrt_special_values), "sqrt table size mismatch"); + static_assert(sizeof(tanh_special_values_l) == sizeof(tanh_special_values), "tanh table size mismatch"); + static_assert(sizeof(rect_special_values_l) == sizeof(rect_special_values), "rect table size mismatch"); + + /* Compare entire arrays with single memcmp calls */ + assert(memcmp(acos_special_values_l, acos_special_values, sizeof(acos_special_values_l)) == 0); + assert(memcmp(acosh_special_values_l, acosh_special_values, sizeof(acosh_special_values_l)) == 0); + assert(memcmp(asinh_special_values_l, asinh_special_values, sizeof(asinh_special_values_l)) == 0); + assert(memcmp(atanh_special_values_l, atanh_special_values, sizeof(atanh_special_values_l)) == 0); + assert(memcmp(cosh_special_values_l, cosh_special_values, sizeof(cosh_special_values_l)) == 0); + assert(memcmp(exp_special_values_l, exp_special_values, sizeof(exp_special_values_l)) == 0); + assert(memcmp(log_special_values_l, log_special_values, sizeof(log_special_values_l)) == 0); + assert(memcmp(sinh_special_values_l, sinh_special_values, sizeof(sinh_special_values_l)) == 0); + assert(memcmp(sqrt_special_values_l, sqrt_special_values, sizeof(sqrt_special_values_l)) == 0); + assert(memcmp(tanh_special_values_l, tanh_special_values, sizeof(tanh_special_values_l)) == 0); + assert(memcmp(rect_special_values_l, rect_special_values, sizeof(rect_special_values_l)) == 0); + return 0; }