]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Avoid divide by zero in default template arguments
authorJonathan Wakely <jwakely@redhat.com>
Thu, 8 Oct 2020 13:01:00 +0000 (14:01 +0100)
committerJonathan Wakely <jwakely@redhat.com>
Thu, 8 Oct 2020 13:45:36 +0000 (14:45 +0100)
My previous attempt to fix this only worked when m is a power of two.
There is still a bug when a=00 and !has_single_bit(m).

Instead of trying to make _Mod work for a==0 this change ensures that we
never instantiate it with a==0. For C++17 we can use if-constexpr, but
otherwise we need to use a different multipler. It doesn't matter what
we use, as it won't actually be called, only instantiated.

libstdc++-v3/ChangeLog:

* include/bits/random.h (__detail::_Mod): Revert last change.
(__detail::__mod): Do not use _Mod for a==0 case.
* testsuite/26_numerics/random/linear_congruential_engine/operators/call.cc:
Check other cases with a==0. Also check runtime results.
* testsuite/26_numerics/random/pr60037-neg.cc: Adjust dg-error
line.

libstdc++-v3/include/bits/random.h
libstdc++-v3/testsuite/26_numerics/random/linear_congruential_engine/operators/call.cc
libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc

index 920f3d91513758e5aa67f79a9b0bd88b18a52de1..0be1191e07de70e793c00ad58bce1cb5c68658d4 100644 (file)
@@ -109,7 +109,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     template<typename _Tp, _Tp __m, _Tp __a, _Tp __c,
             bool __big_enough = (!(__m & (__m - 1))
                                  || (_Tp(-1) - __c) / __a >= __m - 1),
-             bool __schrage_ok = __a != 0 && __m % __a < __m / __a>
+             bool __schrage_ok = __m % __a < __m / __a>
       struct _Mod
       {
        typedef typename _Select_uint_least_t<std::__lg(__a)
@@ -146,7 +146,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     template<typename _Tp, _Tp __m, _Tp __a = 1, _Tp __c = 0>
       inline _Tp
       __mod(_Tp __x)
-      { return _Mod<_Tp, __m, __a, __c>::__calc(__x); }
+      {
+       if _GLIBCXX17_CONSTEXPR (__a == 0)
+         return __c;
+       else
+         {
+           // _Mod must not be instantiated with a == 0
+           constexpr _Tp __a1 = __a ? __a : 1;
+           return _Mod<_Tp, __m, __a1, __c>::__calc(__x);
+         }
+      }
 
     /*
      * An adaptor class for converting the output of any Generator into
index d1fff6d0a5d51316ba2787110c43b374f7093466..0000aa2402f7b16bcbaa6a41047dd2321c2fd4ae 100644 (file)
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-do compile { target c++11 } }
+// { dg-do run { target c++11 } }
 
 #include <random>
+#include <testsuite_hooks.h>
 
-unsigned
+void
 test01()
 {
   std::linear_congruential_engine<unsigned, 0, 0, 0> l;
-  return l(); // this used to result in divide by zero
+  auto r = l(); // this used to result in divide by zero
+  VERIFY( r == 0 );
+  l.seed(2);
+  r = l();
+  VERIFY( r == 0 );
+  VERIFY( l() == 0 );
+}
+
+void
+test02()
+{
+  std::linear_congruential_engine<unsigned, 0, 0, 3> l;
+  auto r = l(); // this used to result in a different divide by zero
+  VERIFY( r == 0 );
+  l.seed(2);
+  r = l();
+  VERIFY( r == 0 );
+  VERIFY( l() == 0 );
+}
+
+void
+test03()
+{
+  std::linear_congruential_engine<unsigned, 0, 2, 3> l;
+  auto r = l();
+  VERIFY( r == 2 );
+  l.seed(4);
+  r = l();
+  VERIFY( r == 2 );
+  VERIFY( l() == 2 );
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
 }
index f808132e9ea47a9276ee7950e19c6414c48c9de1..139abbb305186a8ffdc8b0712b8a2d75cf423a32 100644 (file)
@@ -10,6 +10,6 @@ std::__detail::_Adaptor<std::mt19937, unsigned long> aurng(urng);
 auto x = std::generate_canonical<std::size_t,
                        std::numeric_limits<std::size_t>::digits>(urng);
 
-// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 158 }
+// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 167 }
 
 // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3281 }