From cdd63adfcdcc40cb48fc52bb36c9876a888625cb Mon Sep 17 00:00:00 2001 From: John Maddock Date: Sat, 8 Jun 2013 14:07:21 +0000 Subject: [PATCH] Fix assignment operations to be safe after a move. Added test cases to catch bug case. Refs #8667. [SVN r84687] --- include/boost/multiprecision/gmp.hpp | 10 +++--- include/boost/multiprecision/mpfr.hpp | 49 ++++++++++++++++++++++++--- test/test_move.cpp | 45 ++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 9 deletions(-) diff --git a/include/boost/multiprecision/gmp.hpp b/include/boost/multiprecision/gmp.hpp index 9e6f1579..e20bb915 100644 --- a/include/boost/multiprecision/gmp.hpp +++ b/include/boost/multiprecision/gmp.hpp @@ -1015,8 +1015,9 @@ struct gmp_int explicit gmp_int(const gmp_rational& o); gmp_int& operator = (const gmp_int& o) { - if(o.m_data[0]._mp_d) - mpz_set(m_data, o.m_data); + if(m_data[0]._mp_d == 0) + mpz_init(this->m_data); + mpz_set(m_data, o.m_data); return *this; } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES @@ -1728,8 +1729,9 @@ struct gmp_rational } gmp_rational& operator = (const gmp_rational& o) { - if(o.m_data[0]._mp_num._mp_d) - mpq_set(m_data, o.m_data); + if(m_data[0]._mp_den._mp_d == 0) + mpq_init(m_data); + mpq_set(m_data, o.m_data); return *this; } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES diff --git a/include/boost/multiprecision/mpfr.hpp b/include/boost/multiprecision/mpfr.hpp index b7aa784c..81d8c112 100644 --- a/include/boost/multiprecision/mpfr.hpp +++ b/include/boost/multiprecision/mpfr.hpp @@ -702,21 +702,29 @@ struct mpfr_float_backend : public detail::mpfr_float_impm_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpf_t val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_f(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpz_t val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_z(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpq_t val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_q(this->m_data, val, GMP_RNDN); return *this; } @@ -724,22 +732,30 @@ struct mpfr_float_backend : public detail::mpfr_float_imp mpfr_float_backend& operator=(const mpfr_float_backend& val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set(this->m_data, val.data(), GMP_RNDN); return *this; } template mpfr_float_backend& operator=(const gmp_float& val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_f(this->m_data, val.data(), GMP_RNDN); return *this; } mpfr_float_backend& operator=(const gmp_int& val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_z(this->m_data, val.data(), GMP_RNDN); return *this; } mpfr_float_backend& operator=(const gmp_rational& val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(digits10)); mpfr_set_q(this->m_data, val.data(), GMP_RNDN); return *this; } @@ -803,7 +819,10 @@ struct mpfr_float_backend<0, allocate_dynamic> : public detail::mpfr_float_imp<0 mpfr_float_backend& operator=(const mpfr_float_backend& o) { - mpfr_set_prec(this->m_data, mpfr_get_prec(o.data())); + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, mpfr_get_prec(o.data())); + else + mpfr_set_prec(this->m_data, mpfr_get_prec(o.data())); mpfr_set(this->m_data, o.data(), GMP_RNDN); return *this; } @@ -822,47 +841,67 @@ struct mpfr_float_backend<0, allocate_dynamic> : public detail::mpfr_float_imp<0 } mpfr_float_backend& operator=(const mpfr_t val) { - mpfr_set_prec(this->m_data, mpfr_get_prec(val)); + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, mpfr_get_prec(val)); + else + mpfr_set_prec(this->m_data, mpfr_get_prec(val)); mpfr_set(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpf_t val) { - mpfr_set_prec(this->m_data, mpf_get_prec(val)); + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, mpf_get_prec(val)); + else + mpfr_set_prec(this->m_data, mpf_get_prec(val)); mpfr_set_f(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpz_t val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); mpfr_set_z(this->m_data, val, GMP_RNDN); return *this; } mpfr_float_backend& operator=(const mpq_t val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); mpfr_set_q(this->m_data, val, GMP_RNDN); return *this; } template mpfr_float_backend& operator=(const mpfr_float_backend& val) { - mpfr_set_prec(this->m_data, mpfr_get_prec(val.data())); + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, mpfr_get_prec(val.data())); + else + mpfr_set_prec(this->m_data, mpfr_get_prec(val.data())); mpfr_set(this->m_data, val.data(), GMP_RNDN); return *this; } template mpfr_float_backend& operator=(const gmp_float& val) { - mpfr_set_prec(this->m_data, mpf_get_prec(val.data())); + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, mpf_get_prec(val.data())); + else + mpfr_set_prec(this->m_data, mpf_get_prec(val.data())); mpfr_set_f(this->m_data, val.data(), GMP_RNDN); return *this; } mpfr_float_backend& operator=(const gmp_int& val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); mpfr_set_z(this->m_data, val.data(), GMP_RNDN); return *this; } mpfr_float_backend& operator=(const gmp_rational& val) { + if(this->m_data[0]._mpfr_d == 0) + mpfr_init2(this->m_data, multiprecision::detail::digits10_2_2(get_default_precision())); mpfr_set_q(this->m_data, val.data(), GMP_RNDN); return *this; } diff --git a/test/test_move.cpp b/test/test_move.cpp index a2e8b04c..c5c5ab3b 100644 --- a/test/test_move.cpp +++ b/test/test_move.cpp @@ -84,6 +84,36 @@ void test_std_lib() BOOST_TEST(b == 2); } +template +void test_move_and_assign(T x, A val) +{ + // move away from x, then assign val to x. + T z(x); + T y(std::move(x)); + x.assign(val); + BOOST_CHECK_EQUAL(x, T(val)); + BOOST_CHECK_EQUAL(z, y); +} + +template +void test_move_and_assign() +{ + T x(23); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, static_cast(2)); + test_move_and_assign(x, x); + test_move_and_assign(x, "23"); +} + int main() { @@ -131,6 +161,9 @@ int main() d = std::move(e); e = d; BOOST_TEST(e == d); + + test_move_and_assign(); + test_move_and_assign(); } #endif #ifdef TEST_GMP @@ -170,6 +203,9 @@ int main() d = std::move(e); e = d; BOOST_TEST(e == d); + + test_move_and_assign(); + test_move_and_assign(); } { test_std_lib(); @@ -194,6 +230,8 @@ int main() d = std::move(e); e = d; BOOST_TEST(e == d); + + test_move_and_assign(); } { test_std_lib(); @@ -217,6 +255,8 @@ int main() d = std::move(e); e = d; BOOST_TEST(e == d); + + test_move_and_assign(); } #endif #ifdef TEST_TOMMATH @@ -245,6 +285,8 @@ int main() d = std::move(e); e = d; BOOST_TEST(e == d); + + test_move_and_assign(); } #endif #ifdef TEST_CPP_INT @@ -273,6 +315,9 @@ int main() d = std::move(e); e = d; BOOST_TEST(e == d); + + test_move_and_assign(); + test_move_and_assign(); } #endif return boost::report_errors();