Skip to content

Nondeterministic failures on version 3.2.1 #337

Description

@michaeldiscala

Hi there,

When we bumped our application from version 3.1.9 to version 3.2.1 we started getting nondeterministic failures in our test suite.

The problematic code does:

    ZERO = BigDecimal("0").freeze

and then uses this when calculating an average of an array of number:

      x_average = x_values.sum(ZERO) / x_values.size

The error returned has been:


[2025-06-02T17:48:02Z]      Failure/Error: x_average = x_values.sum(ZERO) / x_values.size
--
  | [2025-06-02T17:48:02Z]
  | [2025-06-02T17:48:02Z]      TypeError:
  | [2025-06-02T17:48:02Z]        Proc can't be coerced into BigDecimal
  | [2025-06-02T17:48:02Z]      # ./lib/utils/regression_line.rb:22:in `/'

but we've also seen it error out with a string type:

String can't be coerced into BigDecimal (TypeError)

      x_average = x_values.sum(ZERO) / x_values.size
                                                                   ^^^^^^^^^^^^^

I initially assumed that we were somehow passing a string into x_values, but since the issue is non-deterministic, I'm not sure how that could be the case. I tried to reproduce by running a similar sum operation in a loop but wasn't able to reproduce there.

Do you have any ideas on what might be causing this after the upgrade? Is there any other debugging information I can provide?

Thank you!
--Mike

Activity

  1. matsimitsu commented on Jun 3, 2025

    @matsimitsu

    I'm also seeing the same, but with array: Array can't be coerced into BigDecimal. I'm not aware of any place where I'd coerce an array into BigDecimal.

  2. tompng commented on Jun 3, 2025

    @tompng
    Member

    Sorry I can't reproduce it.
    Does it happen frequently, rarely or always? Could you provide a reproduction code and ruby -v result?

  3. gmalette commented on Jun 3, 2025

    @gmalette

    I can reproduce this with 100% reliability on ruby=3.4.4 and bigdecimal 3.2.0 and 3.2.1. The only thing that changes is the "what can't be coerced". This is highly sus and likely points to memory corruption related to GC compaction. I've also seen this result in segfaults, presumably if the memory it points to is not a valid VALUE.

    #!/usr/bin/env ruby
    
    require "bundler/inline"
    
    puts "Running with Ruby version: #{RUBY_VERSION}"
    
    gemfile do
      source "https://rubygems.org"
      gem "bigdecimal", "3.2.1"
    end
    
    require "bigdecimal"
    
    ZERO = BigDecimal(0).freeze
    
    GC.verify_compaction_references(expand_heap: true, toward: :empty)
    
    ZERO / BigDecimal(100)
    ❯ ./bigdecimal.rb
    Running with Ruby version: 3.4.4
    bigdecimal.rb:19:in 'BigDecimal#/': #<Class:0x00000001210dde38> can't be coerced into BigDecimal (TypeError)
    
    ZERO / BigDecimal(100)
           ^^^^^^^^^^^^^^^
    
  4. tompng commented on Jun 3, 2025

    @tompng
    Member

    Thank you. I can reproduce it.

    X = BigDecimal('2.5')
    GC.verify_compaction_references(expand_heap: true, toward: :empty)
    
    # Bug existed before v3.1.9
    X**X               # ??? can't be coerced into BigDecimal
    BigMath.log(X, 10) # ??? can't be coerced into BigDecimal
    BigMath.exp(X, 10) # Segmentation fault
    
    # Bug from v3.2.0
    X / 2              # ??? can't be coerced into BigDecimal
  5. michaeldiscala commented on Jun 3, 2025

    @michaeldiscala
    Author

    Thank you for the quick attention here & for the help reproducing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions