]> gcc.gnu.org Git - gcc.git/commitdiff
libstdc++: Fix undefined behaviour in random dist serialization (PR93205)
authorJonathan Wakely <jwakely@redhat.com>
Wed, 26 Feb 2020 16:09:52 +0000 (16:09 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Wed, 26 Feb 2020 16:31:57 +0000 (16:31 +0000)
The deserialization functions for random number distributions fail to
check the stream state before using the extracted values. In some cases
this leads to using indeterminate values to resize a vector, and then
filling that vector with indeterminate values.

No values that affect control flow should be used without checking that a
good value was read from the stream.

Additionally, where reasonable to do so, defer modifying any state in
the distribution until all values have been successfully read, to avoid
modifying some of the distribution's parameters and leaving others
unchanged.

Backport from mainline
2020-01-09  Jonathan Wakely  <jwakely@redhat.com>

PR libstdc++/93205
* include/bits/random.h (operator>>): Check stream operation succeeds.
* include/bits/random.tcc: (operator>>): Likewise.
(__extract_params): New function to fill a vector from a stream.
* testsuite/26_numerics/random/pr60037-neg.cc: Adjust dg-error line.

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/random.h
libstdc++-v3/include/bits/random.tcc
libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc

index 0f8f35d87f8e8ece40406148ce4ce9e833eb37f5..7a18c73063c536dae8c9e0f8d8b36e2bc7e99615 100644 (file)
@@ -1,5 +1,14 @@
 2020-02-26  Jonathan Wakely  <jwakely@redhat.com>
 
+       Backport from mainline
+       2020-01-09  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/93205
+       * include/bits/random.h (operator>>): Check stream operation succeeds.
+       * include/bits/random.tcc (operator>>): Likewise.
+       (__extract_params): New function to fill a vector from a stream.
+       * testsuite/26_numerics/random/pr60037-neg.cc: Adjust dg-error line.
+
        Backport from mainline
        2019-12-10  Jonathan Wakely  <jwakely@redhat.com>
 
index c776dc62d21ad202971113051fb251c00245a704..ccd5c834db852bdbc6b3d22caa1fb191daa9a058 100644 (file)
@@ -3645,8 +3645,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
               std::bernoulli_distribution& __x)
     {
       double __p;
-      __is >> __p;
-      __x.param(bernoulli_distribution::param_type(__p));
+      if (__is >> __p)
+       __x.param(bernoulli_distribution::param_type(__p));
       return __is;
     }
 
index f398150d41605bad62c8b0c75f2f1feaec89450f..b7f9961b85230e78c7b2ae993abde6151638c169 100644 (file)
@@ -902,9 +902,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       _IntType __a, __b;
-      __is >> __a >> __b;
-      __x.param(typename uniform_int_distribution<_IntType>::
-               param_type(__a, __b));
+      if (__is >> __a >> __b)
+       __x.param(typename uniform_int_distribution<_IntType>::
+                 param_type(__a, __b));
 
       __is.flags(__flags);
       return __is;
@@ -964,9 +964,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::skipws);
 
       _RealType __a, __b;
-      __is >> __a >> __b;
-      __x.param(typename uniform_real_distribution<_RealType>::
-               param_type(__a, __b));
+      if (__is >> __a >> __b)
+       __x.param(typename uniform_real_distribution<_RealType>::
+                 param_type(__a, __b));
 
       __is.flags(__flags);
       return __is;
@@ -1108,8 +1108,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::skipws);
 
       double __p;
-      __is >> __p;
-      __x.param(typename geometric_distribution<_IntType>::param_type(__p));
+      if (__is >> __p)
+       __x.param(typename geometric_distribution<_IntType>::param_type(__p));
 
       __is.flags(__flags);
       return __is;
@@ -1225,9 +1225,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _IntType __k;
       double __p;
-      __is >> __k >> __p >> __x._M_gd;
-      __x.param(typename negative_binomial_distribution<_IntType>::
-               param_type(__k, __p));
+      if (__is >> __k >> __p >> __x._M_gd)
+       __x.param(typename negative_binomial_distribution<_IntType>::
+                 param_type(__k, __p));
 
       __is.flags(__flags);
       return __is;
@@ -1435,8 +1435,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::skipws);
 
       double __mean;
-      __is >> __mean >> __x._M_nd;
-      __x.param(typename poisson_distribution<_IntType>::param_type(__mean));
+      if (__is >> __mean >> __x._M_nd)
+       __x.param(typename poisson_distribution<_IntType>::param_type(__mean));
 
       __is.flags(__flags);
       return __is;
@@ -1704,9 +1704,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _IntType __t;
       double __p;
-      __is >> __t >> __p >> __x._M_nd;
-      __x.param(typename binomial_distribution<_IntType>::
-               param_type(__t, __p));
+      if (__is >> __t >> __p >> __x._M_nd)
+       __x.param(typename binomial_distribution<_IntType>::
+                 param_type(__t, __p));
 
       __is.flags(__flags);
       return __is;
@@ -1764,9 +1764,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       _RealType __lambda;
-      __is >> __lambda;
-      __x.param(typename exponential_distribution<_RealType>::
-               param_type(__lambda));
+      if (__is >> __lambda)
+       __x.param(typename exponential_distribution<_RealType>::
+                 param_type(__lambda));
 
       __is.flags(__flags);
       return __is;
@@ -1935,12 +1935,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       double __mean, __stddev;
-      __is >> __mean >> __stddev
-          >> __x._M_saved_available;
-      if (__x._M_saved_available)
-       __is >> __x._M_saved;
-      __x.param(typename normal_distribution<_RealType>::
-               param_type(__mean, __stddev));
+      bool __saved_avail;
+      if (__is >> __mean >> __stddev >> __saved_avail)
+       {
+         if (__saved_avail && (__is >> __x._M_saved))
+           {
+             __x._M_saved_available = __saved_avail;
+             __x.param(typename normal_distribution<_RealType>::
+                       param_type(__mean, __stddev));
+           }
+       }
 
       __is.flags(__flags);
       return __is;
@@ -1998,9 +2002,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       _RealType __m, __s;
-      __is >> __m >> __s >> __x._M_nd;
-      __x.param(typename lognormal_distribution<_RealType>::
-               param_type(__m, __s));
+      if (__is >> __m >> __s >> __x._M_nd)
+       __x.param(typename lognormal_distribution<_RealType>::
+                 param_type(__m, __s));
 
       __is.flags(__flags);
       return __is;
@@ -2070,9 +2074,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       _RealType __n;
-      __is >> __n >> __x._M_gd;
-      __x.param(typename chi_squared_distribution<_RealType>::
-               param_type(__n));
+      if (__is >> __n >> __x._M_gd)
+       __x.param(typename chi_squared_distribution<_RealType>::
+                 param_type(__n));
 
       __is.flags(__flags);
       return __is;
@@ -2157,9 +2161,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       _RealType __a, __b;
-      __is >> __a >> __b;
-      __x.param(typename cauchy_distribution<_RealType>::
-               param_type(__a, __b));
+      if (__is >> __a >> __b)
+       __x.param(typename cauchy_distribution<_RealType>::
+                 param_type(__a, __b));
 
       __is.flags(__flags);
       return __is;
@@ -2235,9 +2239,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       _RealType __m, __n;
-      __is >> __m >> __n >> __x._M_gd_x >> __x._M_gd_y;
-      __x.param(typename fisher_f_distribution<_RealType>::
-               param_type(__m, __n));
+      if (__is >> __m >> __n >> __x._M_gd_x >> __x._M_gd_y)
+       __x.param(typename fisher_f_distribution<_RealType>::
+                 param_type(__m, __n));
 
       __is.flags(__flags);
       return __is;
@@ -2309,8 +2313,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       _RealType __n;
-      __is >> __n >> __x._M_nd >> __x._M_gd;
-      __x.param(typename student_t_distribution<_RealType>::param_type(__n));
+      if (__is >> __n >> __x._M_nd >> __x._M_gd)
+       __x.param(typename student_t_distribution<_RealType>::param_type(__n));
 
       __is.flags(__flags);
       return __is;
@@ -2479,9 +2483,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       _RealType __alpha_val, __beta_val;
-      __is >> __alpha_val >> __beta_val >> __x._M_nd;
-      __x.param(typename gamma_distribution<_RealType>::
-               param_type(__alpha_val, __beta_val));
+      if (__is >> __alpha_val >> __beta_val >> __x._M_nd)
+       __x.param(typename gamma_distribution<_RealType>::
+                 param_type(__alpha_val, __beta_val));
 
       __is.flags(__flags);
       return __is;
@@ -2556,9 +2560,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       _RealType __a, __b;
-      __is >> __a >> __b;
-      __x.param(typename weibull_distribution<_RealType>::
-               param_type(__a, __b));
+      if (__is >> __a >> __b)
+       __x.param(typename weibull_distribution<_RealType>::
+                 param_type(__a, __b));
 
       __is.flags(__flags);
       return __is;
@@ -2632,9 +2636,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       _RealType __a, __b;
-      __is >> __a >> __b;
-      __x.param(typename extreme_value_distribution<_RealType>::
-               param_type(__a, __b));
+      if (__is >> __a >> __b)
+       __x.param(typename extreme_value_distribution<_RealType>::
+                 param_type(__a, __b));
 
       __is.flags(__flags);
       return __is;
@@ -2759,6 +2763,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __os;
     }
 
+namespace __detail
+{
+  template<typename _ValT, typename _CharT, typename _Traits>
+    basic_istream<_CharT, _Traits>&
+    __extract_params(basic_istream<_CharT, _Traits>& __is,
+                    vector<_ValT>& __vals, size_t __n)
+    {
+      __vals.reserve(__n);
+      while (__n--)
+       {
+         _ValT __val;
+         if (__is >> __val)
+           __vals.push_back(__val);
+         else
+           break;
+       }
+      return __is;
+    }
+} // namespace __detail
+
   template<typename _IntType, typename _CharT, typename _Traits>
     std::basic_istream<_CharT, _Traits>&
     operator>>(std::basic_istream<_CharT, _Traits>& __is,
@@ -2771,20 +2795,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       size_t __n;
-      __is >> __n;
-
-      std::vector<double> __prob_vec;
-      __prob_vec.reserve(__n);
-      for (; __n != 0; --__n)
+      if (__is >> __n)
        {
-         double __prob;
-         __is >> __prob;
-         __prob_vec.push_back(__prob);
+         std::vector<double> __prob_vec;
+         if (__detail::__extract_params(__is, __prob_vec, __n))
+           __x.param({__prob_vec.begin(), __prob_vec.end()});
        }
 
-      __x.param(typename discrete_distribution<_IntType>::
-               param_type(__prob_vec.begin(), __prob_vec.end()));
-
       __is.flags(__flags);
       return __is;
     }
@@ -2986,29 +3003,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       size_t __n;
-      __is >> __n;
-
-      std::vector<_RealType> __int_vec;
-      __int_vec.reserve(__n + 1);
-      for (size_t __i = 0; __i <= __n; ++__i)
-       {
-         _RealType __int;
-         __is >> __int;
-         __int_vec.push_back(__int);
-       }
-
-      std::vector<double> __den_vec;
-      __den_vec.reserve(__n);
-      for (size_t __i = 0; __i < __n; ++__i)
+      if (__is >> __n)
        {
-         double __den;
-         __is >> __den;
-         __den_vec.push_back(__den);
+         std::vector<_RealType> __int_vec;
+         if (__detail::__extract_params(__is, __int_vec, __n + 1))
+           {
+             std::vector<double> __den_vec;
+             if (__detail::__extract_params(__is, __den_vec, __n))
+               {
+                 __x.param({ __int_vec.begin(), __int_vec.end(),
+                             __den_vec.begin() });
+               }
+           }
        }
 
-      __x.param(typename piecewise_constant_distribution<_RealType>::
-         param_type(__int_vec.begin(), __int_vec.end(), __den_vec.begin()));
-
       __is.flags(__flags);
       return __is;
     }
@@ -3202,29 +3210,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __is.flags(__ios_base::dec | __ios_base::skipws);
 
       size_t __n;
-      __is >> __n;
-
-      std::vector<_RealType> __int_vec;
-      __int_vec.reserve(__n + 1);
-      for (size_t __i = 0; __i <= __n; ++__i)
+      if (__is >> __n)
        {
-         _RealType __int;
-         __is >> __int;
-         __int_vec.push_back(__int);
-       }
-
-      std::vector<double> __den_vec;
-      __den_vec.reserve(__n + 1);
-      for (size_t __i = 0; __i <= __n; ++__i)
-       {
-         double __den;
-         __is >> __den;
-         __den_vec.push_back(__den);
+         vector<_RealType> __int_vec;
+         if (__detail::__extract_params(__is, __int_vec, __n + 1))
+           {
+             vector<double> __den_vec;
+             if (__detail::__extract_params(__is, __den_vec, __n + 1))
+               {
+                 __x.param({ __int_vec.begin(), __int_vec.end(),
+                             __den_vec.begin() });
+               }
+           }
        }
-
-      __x.param(typename piecewise_linear_distribution<_RealType>::
-         param_type(__int_vec.begin(), __int_vec.end(), __den_vec.begin()));
-
       __is.flags(__flags);
       return __is;
     }
index 13c052daef851a009e76c63cae5239078bebbfa4..f1e40ca2d68b3be650a0385fe6886bb171203814 100644 (file)
@@ -11,4 +11,4 @@ auto x = std::generate_canonical<std::size_t,
 
 // { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 156 }
 
-// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3317 }
+// { dg-error "static assertion failed: template argument must be a floating point type" "" { target *-*-* } 3315 }
This page took 0.073141 seconds and 5 git commands to generate.