Pin frozen messages to their arena to prevent garbage collection. (#13420)

Fixes a class of flaky test failures observed only in the FFI implementation due to garbage collection in between calls to an accessors for a frozen field.

Closes #13420

COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/13420 from protocolbuffers:rub 0ea91165fb
PiperOrigin-RevId: 552602026
pull/13404/head
Jason Lunn 1 year ago committed by Copybara-Service
parent 43e1657cdf
commit 1ce24c5d0c
  1. 6
      ruby/lib/google/protobuf/ffi/internal/arena.rb
  2. 6
      ruby/lib/google/protobuf/ffi/message.rb

@ -35,6 +35,7 @@ module Google
module Protobuf module Protobuf
module Internal module Internal
class Arena class Arena
attr :pinned_messages
# FFI Interface methods and setup # FFI Interface methods and setup
extend ::FFI::DataConverter extend ::FFI::DataConverter
@ -59,6 +60,7 @@ module Google
def initialize(pointer) def initialize(pointer)
@arena = ::FFI::AutoPointer.new(pointer, Google::Protobuf::FFI.method(:free_arena)) @arena = ::FFI::AutoPointer.new(pointer, Google::Protobuf::FFI.method(:free_arena))
@pinned_messages = []
end end
def fuse(other_arena) def fuse(other_arena)
@ -67,6 +69,10 @@ module Google
raise RuntimeError.new "Unable to fuse arenas. This should never happen since Ruby does not use initial blocks" raise RuntimeError.new "Unable to fuse arenas. This should never happen since Ruby does not use initial blocks"
end end
end end
def pin(message)
pinned_messages.push message
end
end end
end end

@ -80,6 +80,12 @@ module Google
instance instance
end end
def freeze
super
@arena.pin self
self
end
def dup def dup
duplicate = self.class.private_constructor(@arena) duplicate = self.class.private_constructor(@arena)
mini_table = Google::Protobuf::FFI.get_mini_table(self.class.descriptor) mini_table = Google::Protobuf::FFI.get_mini_table(self.class.descriptor)

Loading…
Cancel
Save