Bug #7044


BigDecimal#power randomly raises coercion errors

Added by twooster (Tony Wooster) about 10 years ago. Updated almost 10 years ago.

Target version:
ruby -v:
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]


When running the following code:

require 'bigdecimal'

10000.times {'1001.10')**0.75; putc '.' }

The call to ** will sometimes (not always) raise the following trace:

..............................................TypeError: #<Class:0x0000001cd78f40> can't be coerced into BigDecimal
	from (irb):4:in `**'
	from (irb):4:in `block in irb_binding'
	from (irb):3:in `times'
	from (irb):3
	from /home/tony/.rbenv/versions/1.9.3-p194/bin/irb:12:in `<main>'

(The '.'s being the debug print of the putc.) I understand the documentation says only integer powers are supported for BigDecimal, however there is code support for floats and rationals, and it should fail or work reliably either way.

Updated by mame (Yusuke Endoh) about 10 years ago

  • Status changed from Open to Assigned
  • Assignee set to mrkn (Kenta Murata)
  • Target version set to 2.0.0

Confirmed, good catch!

Looks GC issue. An intermediate object seems to be GC'd too early.
The following patch will fix. Mrkn, could you review and commit it if it looks good?

diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index f58b640..36ca77d 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -2016,6 +2016,7 @@ static VALUE
rmpd_power_by_big_decimal(Real const* x, Real const* exp, ssize_t const n)
VALUE log_x, multiplied, y;

  • volatile VALUE obj = exp->obj;

    if (VpIsZero(exp)) {
    return ToValue(VpCreateRbObject(n, "1"));
    @@ -2024,6 +2025,7 @@ rmpd_power_by_big_decimal(Real const* x, Real const* exp, ssize_t const n)
    log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
    multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
    y = BigMath_exp(multiplied, SSIZET2NUM(n));

  • RB_GC_GUARD(obj);

    return y;

Yusuke Endoh

Actions #2

Updated by mrkn (Kenta Murata) almost 10 years ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r38734.
Tony, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.

  • ext/bigdecimal/bigdecimal.c (rmpd_power_by_big_decimal):
    add RB_GC_GUARD to prevent the immediate object is GCed too early.
    This patch was made by Yusuke Endoh. [Bug #7044] [ruby-core:47632]

  • test/bigdecimal/test_bigdecimal.rb: add a reproduction test for
    the issue [Bug #7044]


Also available in: Atom PDF