summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2022-07-03 09:42:44 -0700
committerJeremy Evans <code@jeremyevans.net>2022-07-03 09:42:44 -0700
commitfe6245b4309c855e6aca5b786ad50a72d53d278a (patch)
tree0882a33e2c0b1de50151c8bf6ffb95e7e98fec0c /internal
parentcd34f56d450f2310cceaf4c5f34d23eddfda58e8 (diff)
Fix rb_fix_mul_fix on OpenBSD/mips64
This fixes invalid and inconsistent results for the Fixnum*Fixnum case where the result of the multiplication does not fit in 64-bit on OpenBSD/mips64. For example: $ for x in 1 23; do ruby31 -e 'p(54306000000000*86400)'; done 14409380628474329524 11410664325873689790 Cases where an argument was Bignum, as well as cases where the result of the multiplication fits in 64-bit are fine: $ for x in 1 23; do ruby31 -e 'p(54306000*86400)'; done 4692038400000 4692038400000 $ for x in 1 23; do ruby31 -e 'p(5430600000000000000000*86400)'; done 469203840000000000000000000 469203840000000000000000000 This was originally discovered by running the tests for the openssl gem on OpenBSD/mips64 and having one test fail for a date far in the future. I eventually traced this to the generic multiplication issue. The underlying cause is using the int128_t type. This avoids use of the int128_t type in this case, falling back to the slower conversion code, which in the overflow case, turns the Fixnums into Bignums, then performs the multiplication.
Diffstat (limited to 'internal')
-rw-r--r--internal/fixnum.h2
1 files changed, 1 insertions, 1 deletions
diff --git a/internal/fixnum.h b/internal/fixnum.h
index cdb60ee1ff..8c251adef1 100644
--- a/internal/fixnum.h
+++ b/internal/fixnum.h
@@ -18,7 +18,7 @@
#if HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG
# define DLONG LONG_LONG
# define DL2NUM(x) LL2NUM(x)
-#elif defined(HAVE_INT128_T)
+#elif defined(HAVE_INT128_T) && !(defined(__OpenBSD__) && defined(__mips64__))
# define DLONG int128_t
# define DL2NUM(x) (RB_FIXABLE(x) ? LONG2FIX(x) : rb_int128t2big(x))
VALUE rb_int128t2big(int128_t n); /* in bignum.c */