[Multiprecision] Runtime assertion failure with clang++3.6.0 but not g++4.9.2

Dear all, this is my first post on this mailing list, so hopefully this will all be by the book. Executing the following minimal working example, which is supposed to calculate "3! == 6" via (1) a template function (2) a class template and save the result in a boost::multiprecision::mpz_int, results in unexpected behavior for clang++3.6.0, with the version of my boost library being 1.59.0. The program displays the correct result using g++4.9.2 however: #include <iostream> #include <boost/multiprecision/gmp.hpp> namespace bm = boost::multiprecision; template <std::size_t N> bm::mpz_int factorial() { return N * factorial<N-1>(); } template<> bm::mpz_int factorial<0>() { return 1; } template <std::size_t N> struct factorial2 { static const bm::mpz_int value; }; template<std::size_t N> const bm::mpz_int factorial2<N>::value = N * factorial2<N-1>::value; template<> struct factorial2<0> { static const bm::mpz_int value; }; const bm::mpz_int factorial2<0>::value = 1; int main () { std::cout << factorial<3>() << '\n'; std::cout << factorial2<3>::value << '\n'; return 0; } The output for clang, having been compiled via clang++ -std=c++14 -stdlib=libc++ -DNDEBUG -o main main.cpp -lgmp will result in: 6 0 However, omitting the NDEBUG flag will trigger an assertion failure: main: /usr/include/boost/multiprecision/gmp.hpp:1296: const mpz_t &boost::multiprecision::backends::gmp_int::data() const: Assertion `m_data[0]._mp_d' failed. Aborted (core dumped) Compiling the same program with g++4.9.2 (with or without "-DNDEBUG") yields the expected result: 6 6 What did I miss? Can this behavior indeed be traced down to Boost.Multiprecision, or does it have to do with the initialization order of static const class members? Or something else? Additionally, both variants work correctly with clang when using a built-in type like 'int'. Any help in understanding the problem on hand would be greatly appreciated! Best Regards, mbw

Seems to be that Multiprecision relies on static data that haven't (necessarily) been initialized before your own static members. Works fine if the members are made non-static: #include <iostream> #include <boost/multiprecision/gmp.hpp> namespace bm = boost::multiprecision; template <std::size_t N> struct factorial2 { const bm::mpz_int value = N * factorial2<N-1>().value; }; template<> struct factorial2<0> { const bm::mpz_int value = 1; }; int main() { std::cout << factorial2<3>().value << '\n'; return 0; } On Mon, Feb 8, 2016 at 10:58 AM, <mbw_bst@mailbox.org> wrote:
Dear all,
this is my first post on this mailing list, so hopefully this will all be by the book. Executing the following minimal working example, which is supposed to calculate "3! == 6" via (1) a template function (2) a class template
and save the result in a boost::multiprecision::mpz_int, results in unexpected behavior for clang++3.6.0, with the version of my boost library being 1.59.0.
The program displays the correct result using g++4.9.2 however:
#include <iostream> #include <boost/multiprecision/gmp.hpp>
namespace bm = boost::multiprecision;
template <std::size_t N> bm::mpz_int factorial() { return N * factorial<N-1>(); }
template<> bm::mpz_int factorial<0>() { return 1; }
template <std::size_t N> struct factorial2 { static const bm::mpz_int value; }; template<std::size_t N> const bm::mpz_int factorial2<N>::value = N * factorial2<N-1>::value;
template<> struct factorial2<0> { static const bm::mpz_int value; }; const bm::mpz_int factorial2<0>::value = 1;
int main () { std::cout << factorial<3>() << '\n'; std::cout << factorial2<3>::value << '\n'; return 0; }
The output for clang, having been compiled via
clang++ -std=c++14 -stdlib=libc++ -DNDEBUG -o main main.cpp -lgmp
will result in:
6 0
However, omitting the NDEBUG flag will trigger an assertion failure:
main: /usr/include/boost/multiprecision/gmp.hpp:1296: const mpz_t &boost::multiprecision::backends::gmp_int::data() const: Assertion `m_data[0]._mp_d' failed. Aborted (core dumped)
Compiling the same program with g++4.9.2 (with or without "-DNDEBUG") yields the expected result:
6 6
What did I miss? Can this behavior indeed be traced down to Boost.Multiprecision, or does it have to do with the initialization order of static const class members? Or something else? Additionally, both variants work correctly with clang when using a built-in type like 'int'.
Any help in understanding the problem on hand would be greatly appreciated!
Best Regards,
mbw _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On 08/02/2016 18:51, Jeff Schwab wrote:
Seems to be that Multiprecision relies on static data that haven't (necessarily) been initialized before your own static members. Works fine if the members are made non-static:
There is no static data in mpz_int being relied on here. John.

On Tue, Feb 9, 2016 at 5:08 AM, John Maddock <jz.maddock@googlemail.com> wrote:
There is no static data in mpz_int being relied on here.
OK, but what is causing the initialization order issue? Reordering definitions in the OP's code does not change the error, and the warning is coming from gmp.hpp.

On 09/02/2016 10:35, Jeff Schwab wrote:
On Tue, Feb 9, 2016 at 5:08 AM, John Maddock <jz.maddock@googlemail.com <mailto:jz.maddock@googlemail.com>> wrote:
There is no static data in mpz_int being relied on here.
OK, but what is causing the initialization order issue? Reordering definitions in the OP's code does not change the error, and the warning is coming from gmp.hpp.
The initialization of: factorial2<N>::value depends on factorial2<N-1>::value being already initialized, but there is no guaranteed ordering for initialization of instances of factorial2<M>::value As I understand it, the compiler can choose any order it wants - alphabetical, order of instantiation, random, or "whatever". GCC chooses an order that accidentally works in this particular case, whereas clang does not. John.

However, omitting the NDEBUG flag will trigger an assertion failure:
main: /usr/include/boost/multiprecision/gmp.hpp:1296: const mpz_t &boost::multiprecision::backends::gmp_int::data() const: Assertion `m_data[0]._mp_d' failed. Aborted (core dumped) That indicates that an uninitialized variable was used.
Compiling the same program with g++4.9.2 (with or without "-DNDEBUG") yields the expected result:
6 6
What did I miss? Can this behavior indeed be traced down to Boost.Multiprecision, or does it have to do with the initialization order of static const class members? Or something else?
I would say initialization order.
Additionally, both variants work correctly with clang when using a built-in type like 'int'.
For type int, the values are computed recursively at compile time, for a user-defined-type the values are computed at runtime and you hit initialization-order issues. HTH, John.
participants (3)
-
Jeff Schwab
-
John Maddock
-
mbw_bst@mailbox.org