Also, please CC the libstdc++ list (as required by the https://gcc.gnu.org/lists.html docs) instead of individually CCing maintainers.
On Wed, 8 Jul 2026 at 12:24, Jonathan Wakely <[email protected]> wrote: > > On Wed, 8 Jul 2026 at 03:45, Kito Cheng wrote: > > > > When phi is +/-infinity, the periodicity-reduction step computes > > std::floor(infinity) which returns infinity, then casts it to int. > > That cast is undefined behavior per [conv.fpint] because infinity is > > outside the range of int. A conforming compiler is free to exploit > > this UB; in practice, Clang eliminates the loop-exit check and > > produces an infinite loop. GCC currently does not exploit this > > particular UB, but the cast is still undefined and should be fixed. > > > > Fix by checking std::isfinite(phi) before the floor+cast and throwing > > std::domain_error for non-finite phi. Boost guards against this by > > an overflow check (phi >= max_value<T>()), where -infinity is first > > negated to +infinity by the sign-handling block[1]. > > > > [1] > > https://www.boost.org/doc/libs/1_85_0/boost/math/special_functions/ellint_1.hpp > > > > libstdc++-v3/ChangeLog: > > > > * include/tr1/ell_integral.tcc (__ellint_1): Throw domain_error > > when phi is not finite. > > (__ellint_2): Likewise. > > (__ellint_3): Likewise. > > * testsuite/special_functions/11_ellint_1/check_inf.cc: New test. > > * testsuite/special_functions/12_ellint_2/check_inf.cc: New test. > > * testsuite/special_functions/13_ellint_3/check_inf.cc: New test. > > --- > > libstdc++-v3/include/tr1/ell_integral.tcc | 6 +- > > .../11_ellint_1/check_inf.cc | 87 +++++++++++++++++++ > > .../12_ellint_2/check_inf.cc | 86 ++++++++++++++++++ > > .../13_ellint_3/check_inf.cc | 86 ++++++++++++++++++ > > 4 files changed, 262 insertions(+), 3 deletions(-) > > create mode 100644 > > libstdc++-v3/testsuite/special_functions/11_ellint_1/check_inf.cc > > create mode 100644 > > libstdc++-v3/testsuite/special_functions/12_ellint_2/check_inf.cc > > create mode 100644 > > libstdc++-v3/testsuite/special_functions/13_ellint_3/check_inf.cc > > > > diff --git a/libstdc++-v3/include/tr1/ell_integral.tcc > > b/libstdc++-v3/include/tr1/ell_integral.tcc > > index e78d4e538a6..e2aead73b3b 100644 > > --- a/libstdc++-v3/include/tr1/ell_integral.tcc > > +++ b/libstdc++-v3/include/tr1/ell_integral.tcc > > @@ -223,7 +223,7 @@ namespace tr1 > > > > if (__isnan(__k) || __isnan(__phi)) > > return std::numeric_limits<_Tp>::quiet_NaN(); > > - else if (std::abs(__k) > _Tp(1)) > > + else if ((std::abs(__k) > _Tp(1)) || !std::isfinite(__phi)) > > std::isfinite was added in C++11 so isn't available when using > -std=c++98 -D__STDCPP_WANT_MATH_SPEC_FUNCS__ > > Since isnan was already used above, we only need std::isinf. Please > use __builtin_isinf(__phi) instead. > > > > std::__throw_domain_error(__N("Bad argument in __ellint_1.")); > > else > > { > > @@ -437,7 +437,7 @@ namespace tr1 > > > > if (__isnan(__k) || __isnan(__phi)) > > return std::numeric_limits<_Tp>::quiet_NaN(); > > - else if (std::abs(__k) > _Tp(1)) > > + else if ((std::abs(__k) > _Tp(1)) || !std::isfinite(__phi)) > > std::__throw_domain_error(__N("Bad argument in __ellint_2.")); > > else > > { > > @@ -705,7 +705,7 @@ namespace tr1 > > > > if (__isnan(__k) || __isnan(__nu) || __isnan(__phi)) > > return std::numeric_limits<_Tp>::quiet_NaN(); > > - else if (std::abs(__k) > _Tp(1)) > > + else if ((std::abs(__k) > _Tp(1)) || !std::isfinite(__phi)) > > std::__throw_domain_error(__N("Bad argument in __ellint_3.")); > > else > > { > > diff --git > > a/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_inf.cc > > b/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_inf.cc > > new file mode 100644 > > index 00000000000..c7efdb468bc > > --- /dev/null > > +++ b/libstdc++-v3/testsuite/special_functions/11_ellint_1/check_inf.cc > > @@ -0,0 +1,87 @@ > > +// { dg-do run { target c++17 } } > > +// { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__" } > > + > > +// Copyright (C) 2026 Free Software Foundation, Inc. > > Please read > https://gcc.gnu.org/onlinedocs/libstdc++/manual/test.html#test.new_tests > and remove the copyright and licence headers from the new tests. > > > +// > > +// This file is part of the GNU ISO C++ Library. This library is free > > +// software; you can redistribute it and/or modify it under the > > +// terms of the GNU General Public License as published by the > > +// Free Software Foundation; either version 3, or (at your option) > > +// any later version. > > +// > > +// This library is distributed in the hope that it will be useful, > > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +// GNU General Public License for more details. > > +// > > +// You should have received a copy of the GNU General Public License along > > +// with this library; see the file COPYING3. If not see > > +// <http://www.gnu.org/licenses/>. > > + > > +// 8.1.11 ellint_1 - non-finite phi must not produce UB (PR > > libstdc++/XXXXX) > > Was this patch produced by AI? > Why is there a bugzilla reference to a a non-existent bug? > > > + > > +#include <cmath> > > +#include <limits> > > +#include <stdexcept> > > +#include <testsuite_hooks.h> > > + > > +void > > +test01() > > +{ > > + // +infinity phi should throw domain_error, not loop forever. > > + bool caught = false; > > + try > > + { > > + volatile float r = std::ellint_1f(0.5F, > > + std::numeric_limits<float>::infinity()); > > Why is this volatile? > > > + (void) r; > > + } > > + catch (const std::domain_error&) > > + { > > + caught = true; > > + } > > + VERIFY(caught); > > +} > > + > > +void > > +test02() > > +{ > > + bool caught = false; > > + try > > + { > > + volatile double r = std::ellint_1(0.5, > > + std::numeric_limits<double>::infinity()); > > + (void) r; > > + } > > + catch (const std::domain_error&) > > + { > > + caught = true; > > + } > > + VERIFY(caught); > > +} > > + > > +void > > +test03() > > +{ > > + bool caught = false; > > + try > > + { > > + volatile long double r = std::ellint_1l(0.5L, > > + std::numeric_limits<long double>::infinity()); > > + (void) r; > > + } > > + catch (const std::domain_error&) > > + { > > + caught = true; > > + } > > + VERIFY(caught); > > +} > > + > > +int > > +main() > > +{ > > + test01(); > > + test02(); > > + test03(); > > + return 0; > > +} > > diff --git > > a/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_inf.cc > > b/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_inf.cc > > new file mode 100644 > > index 00000000000..03b8d80dba7 > > --- /dev/null > > +++ b/libstdc++-v3/testsuite/special_functions/12_ellint_2/check_inf.cc > > @@ -0,0 +1,86 @@ > > +// { dg-do run { target c++17 } } > > +// { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__" } > > + > > +// Copyright (C) 2026 Free Software Foundation, Inc. > > +// > > +// This file is part of the GNU ISO C++ Library. This library is free > > +// software; you can redistribute it and/or modify it under the > > +// terms of the GNU General Public License as published by the > > +// Free Software Foundation; either version 3, or (at your option) > > +// any later version. > > +// > > +// This library is distributed in the hope that it will be useful, > > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +// GNU General Public License for more details. > > +// > > +// You should have received a copy of the GNU General Public License along > > +// with this library; see the file COPYING3. If not see > > +// <http://www.gnu.org/licenses/>. > > + > > +// 8.1.12 ellint_2 - non-finite phi must not produce UB (PR > > libstdc++/XXXXX) > > + > > +#include <cmath> > > +#include <limits> > > +#include <stdexcept> > > +#include <testsuite_hooks.h> > > + > > +void > > +test01() > > +{ > > + bool caught = false; > > + try > > + { > > + volatile float r = std::ellint_2f(0.5F, > > + std::numeric_limits<float>::infinity()); > > + (void) r; > > + } > > + catch (const std::domain_error&) > > + { > > + caught = true; > > + } > > + VERIFY(caught); > > +} > > + > > +void > > +test02() > > +{ > > + bool caught = false; > > + try > > + { > > + volatile double r = std::ellint_2(0.5, > > + std::numeric_limits<double>::infinity()); > > + (void) r; > > + } > > + catch (const std::domain_error&) > > + { > > + caught = true; > > + } > > + VERIFY(caught); > > +} > > + > > +void > > +test03() > > +{ > > + bool caught = false; > > + try > > + { > > + volatile long double r = std::ellint_2l(0.5L, > > + std::numeric_limits<long double>::infinity()); > > + (void) r; > > + } > > + catch (const std::domain_error&) > > + { > > + caught = true; > > + } > > + VERIFY(caught); > > +} > > + > > +int > > +main() > > +{ > > + test01(); > > + test02(); > > + test03(); > > + return 0; > > +} > > diff --git > > a/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_inf.cc > > b/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_inf.cc > > new file mode 100644 > > index 00000000000..25b1f909d46 > > --- /dev/null > > +++ b/libstdc++-v3/testsuite/special_functions/13_ellint_3/check_inf.cc > > @@ -0,0 +1,86 @@ > > +// { dg-do run { target c++17 } } > > +// { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__" } > > + > > +// Copyright (C) 2026 Free Software Foundation, Inc. > > +// > > +// This file is part of the GNU ISO C++ Library. This library is free > > +// software; you can redistribute it and/or modify it under the > > +// terms of the GNU General Public License as published by the > > +// Free Software Foundation; either version 3, or (at your option) > > +// any later version. > > +// > > +// This library is distributed in the hope that it will be useful, > > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +// GNU General Public License for more details. > > +// > > +// You should have received a copy of the GNU General Public License along > > +// with this library; see the file COPYING3. If not see > > +// <http://www.gnu.org/licenses/>. > > + > > +// 8.1.13 ellint_3 - non-finite phi must not produce UB (PR > > libstdc++/XXXXX) > > + > > +#include <cmath> > > +#include <limits> > > +#include <stdexcept> > > +#include <testsuite_hooks.h> > > + > > +void > > +test01() > > +{ > > + bool caught = false; > > + try > > + { > > + volatile float r = std::ellint_3f(0.5F, 0.5F, > > + std::numeric_limits<float>::infinity()); > > + (void) r; > > + } > > + catch (const std::domain_error&) > > + { > > + caught = true; > > + } > > + VERIFY(caught); > > +} > > + > > +void > > +test02() > > +{ > > + bool caught = false; > > + try > > + { > > + volatile double r = std::ellint_3(0.5, 0.5, > > + std::numeric_limits<double>::infinity()); > > + (void) r; > > + } > > + catch (const std::domain_error&) > > + { > > + caught = true; > > + } > > + VERIFY(caught); > > +} > > + > > +void > > +test03() > > +{ > > + bool caught = false; > > + try > > + { > > + volatile long double r = std::ellint_3l(0.5L, 0.5L, > > + std::numeric_limits<long double>::infinity()); > > + (void) r; > > + } > > + catch (const std::domain_error&) > > + { > > + caught = true; > > + } > > + VERIFY(caught); > > +} > > + > > +int > > +main() > > +{ > > + test01(); > > + test02(); > > + test03(); > > + return 0; > > +} > > -- > > 2.54.0 > >
