From 15c99df7bca51d33d6d7d7fe26ad7ce66ebb7ac4 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 18 Apr 2022 16:19:20 +0200 Subject: Do not use mp directly in mpz_class This is the difference between f and g in the following, where gcc generates "return 1;" for f and not for g. The aliasing is caused by the functions get_num and get_den in mpq_class. struct mpz_struct { int i; }; typedef mpz_struct mpz_t[1]; struct mpq_struct { mpz_struct num, den; }; typedef mpq_struct mpq_t[1]; struct mpz_class { mpz_t mp; }; struct mpq_class { mpq_t mp; }; int f(mpq_class*q, mpz_class*z){ q->mp->num.i = 1; z->mp->i = 2; return q->mp->num.i; } int g(mpq_class*q, mpz_class*z){ q->mp->num.i = 1; int*p=&z->mp->i; *p = 2; return q->mp->num.i; } --- gmpxx.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'gmpxx.h') diff --git a/gmpxx.h b/gmpxx.h index 0d5c6e374..b7ed06a4d 100644 --- a/gmpxx.h +++ b/gmpxx.h @@ -1580,7 +1580,7 @@ private: void assign_ui(unsigned long l) { if (__GMPXX_CONSTANT_TRUE(l == 0)) - mp->_mp_size = 0; + __get_mp()->_mp_size = 0; else mpz_set_ui(mp, l); } @@ -1634,7 +1634,7 @@ public: __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); } #if __GMPXX_USE_CXX11 __gmp_expr(__gmp_expr &&z) noexcept - { *mp = *z.mp; mpz_init(z.mp); } + { *__get_mp() = *z.__get_mp(); mpz_init(z.mp); } #endif template __gmp_expr(const __gmp_expr &expr) @@ -1666,7 +1666,8 @@ public: ~__gmp_expr() { mpz_clear(mp); } - void swap(__gmp_expr& z) __GMPXX_NOEXCEPT { std::swap(*mp, *z.mp); } + void swap(__gmp_expr& z) __GMPXX_NOEXCEPT + { std::swap(*__get_mp(), *z.__get_mp()); } // assignment operators __gmp_expr & operator=(const __gmp_expr &z) @@ -1728,7 +1729,7 @@ public: // bool fits_ldouble_p() const { return mpz_fits_ldouble_p(mp); } #if __GMPXX_USE_CXX11 - explicit operator bool() const { return mp->_mp_size != 0; } + explicit operator bool() const { return __get_mp()->_mp_size != 0; } #endif // member operators @@ -1896,9 +1897,11 @@ public: // conversion functions - // casting a reference to an mpz_t to mpz_class & is a dirty hack, - // but works because the internal representation of mpz_class is - // exactly an mpz_t + // casting a reference to an mpz_t to mpz_class & is a dirty hack. + // It kind of works because the internal representation of mpz_class is + // exactly an mpz_t, but compilers are allowed to assume that mpq_class + // and mpz_class do not alias... In mpz_class, we avoid using mp directly, + // to reduce the risks of such problematic optimizations. const mpz_class & get_num() const { return reinterpret_cast(*mpq_numref(mp)); } mpz_class & get_num() -- cgit v1.2.1