diff --git a/lib/datadog/core/configuration/settings.rb b/lib/datadog/core/configuration/settings.rb index 29de5f6c24f..16ae149622f 100644 --- a/lib/datadog/core/configuration/settings.rb +++ b/lib/datadog/core/configuration/settings.rb @@ -314,15 +314,28 @@ def initialize(*_) # Can be used to enable/disable the Datadog::Profiling.allocation_count feature. # - # This feature is safe and enabled by default on Ruby 2.x, but - # on Ruby 3.x it can break in applications that make use of Ractors due to two Ruby VM bugs: - # https://bugs.ruby-lang.org/issues/19112 AND https://bugs.ruby-lang.org/issues/18464. + # This feature is safe and enabled by default on Ruby 2.x, but has a few caveats on Ruby 3.x. # - # If you use Ruby 3.x and your application does not use Ractors (or if your Ruby has been patched), the - # feature is fully safe to enable and this toggle can be used to do so. + # Caveat 1 (severe): + # On Ruby versions 3.0 (all), 3.1.0 to 3.1.3, and 3.2.0 to 3.2.2 this is disabled by default because it + # can trigger a VM bug that causes a segmentation fault during garbage collection of Ractors + # (https://bugs.ruby-lang.org/issues/18464). We don't recommend using this feature on such Rubies. + # This bug is fixed on Ruby versions 3.1.4, 3.2.3 and 3.3.0. # - # @default `true` on Ruby 2.x, `false` on Ruby 3.x - option :allocation_counting_enabled, default: RUBY_VERSION.start_with?('2.') + # Caveat 2 (annoyance): + # On all known versions of Ruby 3.x, due to https://bugs.ruby-lang.org/issues/19112, when a ractor gets + # garbage collected, Ruby will disable all active tracepoints, which this feature internally relies on. + # Thus this feature is only usable if you're not using Ractors. + # + # @default `true` on Ruby 2.x and 3.1.4+, 3.2.3+ and 3.3.0+; `false` for Ruby 3.0 and unpatched Rubies. + option :allocation_counting_enabled do |o| + o.default do + RUBY_VERSION.start_with?('2.') || + (RUBY_VERSION.start_with?('3.1.') && RUBY_VERSION >= '3.1.4') || + (RUBY_VERSION.start_with?('3.2.') && RUBY_VERSION >= '3.2.3') || + RUBY_VERSION >= '3.3.' + end + end # Can be used to disable checking which version of `libmysqlclient` is being used by the `mysql2` gem. # diff --git a/spec/datadog/core/configuration/settings_spec.rb b/spec/datadog/core/configuration/settings_spec.rb index 50786b015c3..8e676e504d6 100644 --- a/spec/datadog/core/configuration/settings_spec.rb +++ b/spec/datadog/core/configuration/settings_spec.rb @@ -500,16 +500,25 @@ describe '#allocation_counting_enabled' do subject(:allocation_counting_enabled) { settings.profiling.advanced.allocation_counting_enabled } - context 'on Ruby 2.x' do - before { skip("Spec doesn't run on Ruby 3.x") unless RUBY_VERSION.start_with?('2.') } + before { stub_const('RUBY_VERSION', testing_version) } + context 'on Ruby 2.x' do + let(:testing_version) { '2.3.0 ' } it { is_expected.to be true } end - context 'on Ruby 3.x' do - before { skip("Spec doesn't run on Ruby 2.x") if RUBY_VERSION.start_with?('2.') } + ['3.0.0', '3.1.0', '3.1.3', '3.2.0', '3.2.2'].each do |broken_ruby| + context "on a Ruby 3 version affected by https://bugs.ruby-lang.org/issues/18464 (#{broken_ruby})" do + let(:testing_version) { broken_ruby } + it { is_expected.to be false } + end + end - it { is_expected.to be false } + ['3.1.4', '3.2.3', '3.3.0'].each do |fixed_ruby| + context "on a Ruby 3 version where https://bugs.ruby-lang.org/issues/18464 is fixed (#{fixed_ruby})" do + let(:testing_version) { fixed_ruby } + it { is_expected.to be true } + end end end