From: Jonathan Wakely Date: Wed, 26 Feb 2020 16:31:19 +0000 (+0000) Subject: libstdc++: Fix undefined behaviour in random dist serialization (PR93205) X-Git-Tag: releases/gcc-9.3.0~72 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a29236a23c03fe08998b81a0ef1f67e7ea185ba3;p=thirdparty%2Fgcc.git libstdc++: Fix undefined behaviour in random dist serialization (PR93205) 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 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. --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index cf6c95267e3e..a0dc8ee05f9f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,14 @@ 2020-02-26 Jonathan Wakely + Backport from mainline + 2020-01-09 Jonathan Wakely + + 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 diff --git a/libstdc++-v3/include/bits/random.h b/libstdc++-v3/include/bits/random.h index 2b1df4cb59ea..14f680f50c47 100644 --- a/libstdc++-v3/include/bits/random.h +++ b/libstdc++-v3/include/bits/random.h @@ -3715,8 +3715,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; } diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc index b80ab82ba154..9e0f1322f330 100644 --- a/libstdc++-v3/include/bits/random.tcc +++ b/libstdc++-v3/include/bits/random.tcc @@ -905,9 +905,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; @@ -967,9 +967,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; @@ -1111,8 +1111,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; @@ -1228,9 +1228,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; @@ -1438,8 +1438,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; @@ -1707,9 +1707,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; @@ -1767,9 +1767,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; @@ -1938,12 +1938,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; @@ -2001,9 +2005,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; @@ -2073,9 +2077,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; @@ -2160,9 +2164,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; @@ -2238,9 +2242,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; @@ -2312,8 +2316,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; @@ -2482,9 +2486,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; @@ -2559,9 +2563,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; @@ -2635,9 +2639,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; @@ -2762,6 +2766,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __os; } +namespace __detail +{ + template + 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 std::basic_istream<_CharT, _Traits>& operator>>(std::basic_istream<_CharT, _Traits>& __is, @@ -2774,20 +2798,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __is.flags(__ios_base::dec | __ios_base::skipws); size_t __n; - __is >> __n; - - std::vector __prob_vec; - __prob_vec.reserve(__n); - for (; __n != 0; --__n) + if (__is >> __n) { - double __prob; - __is >> __prob; - __prob_vec.push_back(__prob); + std::vector __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; } @@ -2989,29 +3006,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 __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 __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; } @@ -3205,29 +3213,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 __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 __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; } diff --git a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc index f365337e789c..b360203adf47 100644 --- a/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc +++ b/libstdc++-v3/testsuite/26_numerics/random/pr60037-neg.cc @@ -12,4 +12,4 @@ auto x = std::generate_canonical