Skip to content

Span#deep_dup is a shallow dup #3039

Description

@SeanLF

Span#deep_dup (span.rb:245) is def deep_dup; dup; end. The copy shares @data, @tags, and @span_recorder with the original, so writing to the copy mutates the original.

Scope#dup calls it on every push_scope and every capture_event, so a "copied" scope holding a plain child span shares the parent's recorder.

Making it a real deep copy changes allocation behaviour on a hot path. Happy to open a PR to fix this once maintainers weigh in

Failing spec

Drop in sentry-ruby/spec/ and run bundle exec rspec spec/span_deep_dup_spec.rb. Both examples fail on master.

# Run from sentry-ruby/: bundle exec rspec path/to/span_deep_dup_spec.rb
require "spec_helper"

RSpec.describe "Span#deep_dup" do
  before { perform_basic_setup { |config| config.traces_sample_rate = 1.0 } }

  let(:span) do
    transaction = Sentry.start_transaction(name: "t", op: "op")
    transaction.start_child(op: "child")
  end

  it "does not share mutable state with the original" do
    span.set_data("original", true)
    copy = span.deep_dup

    copy.set_data("written_via_copy", true)

    expect(span.data).not_to have_key("written_via_copy")
  end

  it "gives the copy its own data, tags and span recorder" do
    copy = span.deep_dup

    aggregate_failures do
      expect(copy.data).not_to be(span.data)
      expect(copy.tags).not_to be(span.tags)
      expect(copy.span_recorder).not_to be(span.span_recorder)
    end
  end
end

Activity

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

Metadata

Metadata

Assignees

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions