| Make GMP compile in a noexcept environment |
| |
| GMP throws exceptions to indicate errors like failed allocation or negative |
| factorials. Change these to print a terse error message and SIGABRT. |
| |
| Ideally, these would `LOG(FATAL)`. However, giving GMP an Abseil dependency |
| breaks Haskell binaries. (The problematic dependency chain appears to be |
| Haskell -> GMP -> Abseil -> libunwind.) Instead, just log using `std::cerr` and |
| call `std::abort`; the abnormal termination will trigger a stack trace in |
| google3 binaries anyway. |
| |
| This is an updated version of cl/50915228. |
| |
| --- a/gmpxx.h |
| +++ b/gmpxx.h |
| @@ -39,7 +39,12 @@ see https://www.gnu.org/licenses/. */ |
| #include <utility> |
| #include <algorithm> /* swap */ |
| #include <string> |
| +#ifdef __EXCEPTIONS |
| #include <stdexcept> |
| +#else |
| +#include <cstdlib> |
| +#include <iostream> |
| +#endif |
| #include <cfloat> |
| #include <gmp.h> |
| |
| @@ -1240,7 +1245,14 @@ struct __gmp_fac_function |
| static void eval(mpz_ptr z, signed long l) |
| { |
| if (l < 0) |
| +#ifdef __EXCEPTIONS |
| throw std::domain_error ("factorial(negative)"); |
| +#else |
| + { |
| + std::cerr << "std::domain_error: factorial(negative)\n"; |
| + std::abort(); |
| + } |
| +#endif |
| eval(z, static_cast<unsigned long>(l)); |
| } |
| static void eval(mpz_ptr z, mpz_srcptr w) |
| @@ -1248,9 +1260,23 @@ struct __gmp_fac_function |
| if (!mpz_fits_ulong_p(w)) |
| { |
| if (mpz_sgn(w) < 0) |
| +#ifdef __EXCEPTIONS |
| throw std::domain_error ("factorial(negative)"); |
| +#else |
| + { |
| + std::cerr << "std::domain_error: factorial(negative)\n"; |
| + std::abort(); |
| + } |
| +#endif |
| else |
| +#ifdef __EXCEPTIONS |
| throw std::bad_alloc(); // or std::overflow_error ("factorial")? |
| +#else |
| + { |
| + std::cerr << "std::bad_alloc\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| eval(z, mpz_get_ui(w)); |
| } |
| @@ -1264,7 +1290,14 @@ struct __gmp_primorial_function |
| static void eval(mpz_ptr z, signed long l) |
| { |
| if (l < 0) |
| +#ifdef __EXCEPTIONS |
| throw std::domain_error ("primorial(negative)"); |
| +#else |
| + { |
| + std::cerr << "std::domain_error: primorial(negative)\n"; |
| + std::abort(); |
| + } |
| +#endif |
| eval(z, static_cast<unsigned long>(l)); |
| } |
| static void eval(mpz_ptr z, mpz_srcptr w) |
| @@ -1272,9 +1305,23 @@ struct __gmp_primorial_function |
| if (!mpz_fits_ulong_p(w)) |
| { |
| if (mpz_sgn(w) < 0) |
| +#ifdef __EXCEPTIONS |
| throw std::domain_error ("primorial(negative)"); |
| +#else |
| + { |
| + std::cerr << "std::domain_error: primorial(negative)\n"; |
| + std::abort(); |
| + } |
| +#endif |
| else |
| +#ifdef __EXCEPTIONS |
| throw std::bad_alloc(); // or std::overflow_error ("primorial")? |
| +#else |
| + { |
| + std::cerr << "std::bad_alloc\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| eval(z, mpz_get_ui(w)); |
| } |
| @@ -1299,7 +1346,14 @@ struct __gmp_fib_function |
| static void eval(mpz_ptr z, mpz_srcptr w) |
| { |
| if (!mpz_fits_slong_p(w)) |
| +#ifdef __EXCEPTIONS |
| throw std::bad_alloc(); // or std::overflow_error ("fibonacci")? |
| +#else |
| + { |
| + std::cerr << "std::bad_alloc\n"; |
| + std::abort(); |
| + } |
| +#endif |
| eval(z, mpz_get_si(w)); |
| } |
| static void eval(mpz_ptr z, double d) |
| @@ -1650,7 +1704,14 @@ public: |
| if (mpz_init_set_str (mp, s, base) != 0) |
| { |
| mpz_clear (mp); |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpz_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpz_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| } |
| explicit __gmp_expr(const std::string &s, int base = 0) |
| @@ -1658,7 +1719,14 @@ public: |
| if (mpz_init_set_str(mp, s.c_str(), base) != 0) |
| { |
| mpz_clear (mp); |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpz_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpz_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| } |
| |
| @@ -1685,13 +1753,27 @@ public: |
| __gmp_expr & operator=(const char *s) |
| { |
| if (mpz_set_str (mp, s, 0) != 0) |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpz_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpz_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| return *this; |
| } |
| __gmp_expr & operator=(const std::string &s) |
| { |
| if (mpz_set_str(mp, s.c_str(), 0) != 0) |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpz_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpz_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| return *this; |
| } |
| |
| @@ -1828,7 +1910,14 @@ public: |
| else if (mpq_set_str(mp, s, base) != 0) |
| { |
| mpq_clear (mp); |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpq_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpq_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| } |
| explicit __gmp_expr(const std::string &s, int base = 0) |
| @@ -1837,7 +1926,14 @@ public: |
| if (mpq_set_str (mp, s.c_str(), base) != 0) |
| { |
| mpq_clear (mp); |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpq_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpq_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| } |
| explicit __gmp_expr(mpq_srcptr q) |
| @@ -1874,13 +1970,27 @@ public: |
| __gmp_expr & operator=(const char *s) |
| { |
| if (mpq_set_str (mp, s, 0) != 0) |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpq_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpq_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| return *this; |
| } |
| __gmp_expr & operator=(const std::string &s) |
| { |
| if (mpq_set_str(mp, s.c_str(), 0) != 0) |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpq_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpq_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| return *this; |
| } |
| |
| @@ -2038,7 +2148,14 @@ public: |
| if (mpf_init_set_str (mp, s, 0) != 0) |
| { |
| mpf_clear (mp); |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpf_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpf_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| } |
| __gmp_expr(const char *s, mp_bitcnt_t prec, int base = 0) |
| @@ -2047,7 +2164,14 @@ public: |
| if (mpf_set_str(mp, s, base) != 0) |
| { |
| mpf_clear (mp); |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpf_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpf_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| } |
| explicit __gmp_expr(const std::string &s) |
| @@ -2055,7 +2179,14 @@ public: |
| if (mpf_init_set_str(mp, s.c_str(), 0) != 0) |
| { |
| mpf_clear (mp); |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpf_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpf_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| } |
| __gmp_expr(const std::string &s, mp_bitcnt_t prec, int base = 0) |
| @@ -2064,7 +2195,14 @@ public: |
| if (mpf_set_str(mp, s.c_str(), base) != 0) |
| { |
| mpf_clear (mp); |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpf_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpf_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| } |
| |
| @@ -2093,13 +2231,27 @@ public: |
| __gmp_expr & operator=(const char *s) |
| { |
| if (mpf_set_str (mp, s, 0) != 0) |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpf_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpf_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| return *this; |
| } |
| __gmp_expr & operator=(const std::string &s) |
| { |
| if (mpf_set_str(mp, s.c_str(), 0) != 0) |
| +#ifdef __EXCEPTIONS |
| throw std::invalid_argument ("mpf_set_str"); |
| +#else |
| + { |
| + std::cerr << "std::invalid_argument: mpf_set_str\n"; |
| + std::abort(); |
| + } |
| +#endif |
| return *this; |
| } |
| |
| @@ -3505,7 +3657,14 @@ public: |
| mp_bitcnt_t size) |
| { |
| if (f (state, size) == 0) |
| +#ifdef __EXCEPTIONS |
| throw std::length_error ("gmp_randinit_lc_2exp_size"); |
| +#else |
| + { |
| + std::cerr << "std::length_error: gmp_randinit_lc_2exp_size\n"; |
| + std::abort(); |
| + } |
| +#endif |
| } |
| |
| ~gmp_randclass() { gmp_randclear(state); } |