Skip to content

Commit e48df01

Browse files
committed
Implement a simpler regression test for #341
What is happening is that when we call into a recursive packing proc, we first save the packer buffer state onto the stack and then reset the buffer. Once we return from the proc, the original buffer state is copied back. The problem with this is that if any of the chunk has a mapped string then they are not reachable by any Ruby object and may be garbage collected at any moment.
1 parent 79027da commit e48df01

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

bin/rspec

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
#
5+
# This file was generated by Bundler.
6+
#
7+
# The application 'rspec' is installed as part of a gem, and
8+
# this file is here to facilitate running it.
9+
#
10+
11+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12+
13+
bundle_binstub = File.expand_path("bundle", __dir__)
14+
15+
if File.file?(bundle_binstub)
16+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17+
load(bundle_binstub)
18+
else
19+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21+
end
22+
end
23+
24+
require "rubygems"
25+
require "bundler/setup"
26+
27+
load Gem.bin_path("rspec-core", "rspec")

spec/packer_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,4 +589,31 @@ def to_msgpack_ext
589589
GC.stress = stress
590590
end
591591
end
592+
593+
it "doesn't crash when using recursive packers concurrently" do
594+
hash_with_indifferent_access = Class.new(Hash)
595+
msgpack = MessagePack::Factory.new
596+
msgpack.register_type(
597+
0x02,
598+
hash_with_indifferent_access,
599+
packer: ->(value, packer) do
600+
packer.write("a".b * 600_0000) # Over MSGPACK_BUFFER_STRING_WRITE_REFERENCE_DEFAULT
601+
packer.write(value.to_h)
602+
GC.start(full_mark: true, immediate_mark: true, immediate_sweep: true)
603+
end,
604+
unpacker: ->(unpacker) { hash_with_indifferent_access.new(unpacker.read) },
605+
recursive: true
606+
)
607+
608+
packer = msgpack.packer
609+
610+
top_hash = hash = hash_with_indifferent_access.new
611+
10.times do
612+
hash["a"] = new_hash = hash_with_indifferent_access.new
613+
hash = new_hash
614+
end
615+
packer.write(top_hash)
616+
packer.write(top_hash)
617+
packer.full_pack
618+
end
592619
end

0 commit comments

Comments
 (0)