Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Can't modify frozen Hash error when evaluating layout containing DataConverter #1056

@mvz

Description

@mvz

I'm getting build failures in gir_ffi with FFI 1.16.0 and up:

/home/matijs/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/ffi-1.16.2/lib/ffi/types.rb:90:in `find_type': can't modify frozen Hash: {:void=>#<FFI::Type::Builtin::VOID size=1 alignment=1>, :bool=>#<FFI::Type::Builtin::BOOL size=1 alignment=1>, :string=>#<FFI::Type::Builtin::STRING size=8 alignment=8>, :char=>#<FFI::Type::Builtin::INT8 size=1 alignment=1>, :uchar=>#<FFI::Type::Builtin::UINT8 size=1 alignment=1>, :short=>#<FFI::Type::Builtin::INT16 size=2 alignment=2>, :ushort=>#<FFI::Type::Builtin::UINT16 size=2 alignment=2>, :int=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :uint=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :long=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :ulong=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :long_long=>#<FFI::Type::Builtin::INT64 size=8 alignment=8>, :ulong_long=>#<FFI::Type::Builtin::UINT64 size=8 alignment=8>, :float=>#<FFI::Type::Builtin::FLOAT32 size=4 alignment=4>, :double=>#<FFI::Type::Builtin::FLOAT64 size=8 alignment=8>, :long_double=>#<FFI::Type::Builtin::LONGDOUBLE size=16 alignment=16>, :pointer=>#<FFI::Type::Builtin::POINTER size=8 alignment=8>, :int8=>#<FFI::Type::Builtin::INT8 size=1 alignment=1>, :uint8=>#<FFI::Type::Builtin::UINT8 size=1 alignment=1>, :int16=>#<FFI::Type::Builtin::INT16 size=2 alignment=2>, :uint16=>#<FFI::Type::Builtin::UINT16 size=2 alignment=2>, :int32=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :uint32=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :int64=>#<FFI::Type::Builtin::INT64 size=8 alignment=8>, :uint64=>#<FFI::Type::Builtin::UINT64 size=8 alignment=8>, :buffer_in=>#<FFI::Type::Builtin::BUFFER_IN size=8 alignment=8>, :buffer_out=>#<FFI::Type::Builtin::BUFFER_OUT size=8 alignment=8>, :buffer_inout=>#<FFI::Type::Builtin::BUFFER_INOUT size=8 alignment=8>, :varargs=>#<FFI::Type::Builtin::VARARGS size=1 alignment=1>, FFI::StrPtrConverter=>#<FFI::Type::Mapped::0x0000559c72f3b2c0 size=8 alignment=8>, :strptr=>#<FFI::Type::Mapped::0x0000559c72f3b2c0 size=8 alignment=8>, :"*__caddr_t"=>#<FFI::Type::Builtin::INT8 size=1 alignment=1>, :__blkcnt64_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__blkcnt_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__blksize_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__clock_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__clockid_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :__daddr_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :__dev_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__fd_mask=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__fsblkcnt64_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__fsblkcnt_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__fsfilcnt64_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__fsfilcnt_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__fsword_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__gid_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :__id_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :__ino64_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__ino_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__int16_t=>#<FFI::Type::Builtin::INT16 size=2 alignment=2>, :__int32_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :__int64_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__int8_t=>#<FFI::Type::Builtin::INT8 size=1 alignment=1>, :__intmax_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__intptr_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__key_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :__loff_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__mode_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :__nlink_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__off64_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__off_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__pid_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :__priority_which_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :__quad_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__rlim64_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__rlim_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__rlimit_resource_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :__rusage_who_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :__sig_atomic_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :__socklen_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :__ssize_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__suseconds_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__syscall_slong_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__syscall_ulong_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__time_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :__timer_t=>#<FFI::Type::Builtin::POINTER size=8 alignment=8>, :__u_char=>#<FFI::Type::Builtin::UINT8 size=1 alignment=1>, :__u_int=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :__u_long=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__u_quad_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__u_short=>#<FFI::Type::Builtin::UINT16 size=2 alignment=2>, :__uid_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :__uint16_t=>#<FFI::Type::Builtin::UINT16 size=2 alignment=2>, :__uint32_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :__uint64_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__uint8_t=>#<FFI::Type::Builtin::UINT8 size=1 alignment=1>, :__uintmax_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :__useconds_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :blkcnt_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :blksize_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :clock_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :clockid_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :daddr_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :dev_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :fd_mask=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :fsblkcnt_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :fsfilcnt_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :gid_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :id_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :in_addr_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :in_port_t=>#<FFI::Type::Builtin::UINT16 size=2 alignment=2>, :ino_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :int16_t=>#<FFI::Type::Builtin::INT16 size=2 alignment=2>, :int32_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :int64_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :int8_t=>#<FFI::Type::Builtin::INT8 size=1 alignment=1>, :int_fast16_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :int_fast32_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :int_fast64_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :int_fast8_t=>#<FFI::Type::Builtin::INT8 size=1 alignment=1>, :int_least32_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :int_least64_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :int_least8_t=>#<FFI::Type::Builtin::INT8 size=1 alignment=1>, :intmax_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :intptr_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :key_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :loff_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :mode_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :nlink_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :off_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :pid_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :pthread_key_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :pthread_once_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :pthread_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :ptrdiff_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :quad_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :register_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :rlim_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :sa_family_t=>#<FFI::Type::Builtin::UINT16 size=2 alignment=2>, :size_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :socklen_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :ssize_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :suseconds_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :time_t=>#<FFI::Type::Builtin::LONG size=8 alignment=8>, :timer_t=>#<FFI::Type::Builtin::POINTER size=8 alignment=8>, :u_char=>#<FFI::Type::Builtin::UINT8 size=1 alignment=1>, :u_int=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :u_int16_t=>#<FFI::Type::Builtin::UINT16 size=2 alignment=2>, :u_int32_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :u_int64_t=>#<FFI::Type::Builtin::UINT64 size=8 alignment=8>, :u_int8_t=>#<FFI::Type::Builtin::UINT8 size=1 alignment=1>, :u_long=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :u_quad_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :u_short=>#<FFI::Type::Builtin::UINT16 size=2 alignment=2>, :uid_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :uint16_t=>#<FFI::Type::Builtin::UINT16 size=2 alignment=2>, :uint32_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :uint64_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :uint8_t=>#<FFI::Type::Builtin::UINT8 size=1 alignment=1>, :uint_fast16_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :uint_fast32_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :uint_fast64_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :uint_fast8_t=>#<FFI::Type::Builtin::UINT8 size=1 alignment=1>, :uint_least16_t=>#<FFI::Type::Builtin::UINT16 size=2 alignment=2>, :uint_least32_t=>#<FFI::Type::Builtin::UINT32 size=4 alignment=4>, :uint_least64_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :uint_least8_t=>#<FFI::Type::Builtin::UINT8 size=1 alignment=1>, :uintmax_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :uintptr_t=>#<FFI::Type::Builtin::ULONG size=8 alignment=8>, :wchar_t=>#<FFI::Type::Builtin::INT32 size=4 alignment=4>, :caddr_t=>#<FFI::Type::Builtin::POINTER size=8 alignment=8>} (FrozenError)
	from /home/matijs/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/ffi-1.16.2/lib/ffi/struct.rb:279:in `find_type'
	from /home/matijs/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/ffi-1.16.2/lib/ffi/struct.rb:272:in `find_field_type'
	from /home/matijs/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/ffi-1.16.2/lib/ffi/struct.rb:269:in `find_field_type'
	from /home/matijs/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/ffi-1.16.2/lib/ffi/struct.rb:312:in `array_layout'
	from /home/matijs/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/ffi-1.16.2/lib/ffi/struct.rb:218:in `layout'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi/builders/with_layout.rb:25:in `block in setup_layout'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi/builders/with_layout.rb:24:in `class_eval'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi/builders/with_layout.rb:24:in `setup_layout'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi/builders/struct_like.rb:12:in `setup_class'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi/builders/base_type_builder.rb:22:in `instantiate_class'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi/builders/base_type_builder.rb:17:in `build_class'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi/builders/type_builder.rb:37:in `build'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi/builder.rb:17:in `build_class'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi/builders/module_builder.rb:40:in `build_namespaced_class'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi/module_base.rb:26:in `load_class'
	from /home/matijs/Projects/gir_ffi/lib/ffi-gobject/value.rb:3:in `<top (required)>'
	from <internal:/home/matijs/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
	from <internal:/home/matijs/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
	from /home/matijs/Projects/gir_ffi/lib/ffi-gobject.rb:8:in `<top (required)>'
	from <internal:/home/matijs/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
	from <internal:/home/matijs/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
	from /home/matijs/Projects/gir_ffi/lib/gir_ffi.rb:6:in `<top (required)>'
	from <internal:/home/matijs/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
	from <internal:/home/matijs/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
	from /home/matijs/Projects/gir_ffi/test/gir_ffi_test_helper.rb:5:in `<top (required)>'
	from <internal:/home/matijs/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
	from <internal:/home/matijs/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
	from /home/matijs/Projects/gir_ffi/test/gir_ffi/allocation_helper_test.rb:3:in `<top (required)>'
	from <internal:/home/matijs/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
	from <internal:/home/matijs/.rbenv/versions/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
	from /home/matijs/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rake-13.0.6/lib/rake/rake_test_loader.rb:21:in `block in <main>'
	from /home/matijs/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rake-13.0.6/lib/rake/rake_test_loader.rb:6:in `select'
	from /home/matijs/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/rake-13.0.6/lib/rake/rake_test_loader.rb:6:in `<main>'

I've investigated and gotten this far:

  • The offending layout definition is :g_type, :uint64, 0, :data, [GObject::Private___Value__data__union, 2], 8
  • The problematic type in the definition is GObject::Private___Value__data__union, a class that extends FFI::DataConverter.
  • The problematic line in FFI is https://github.com/ffi/ffi/blob/v1.16.2/lib/ffi/types.rb#L90, which is executed when the type to be found is a DataConverter:
    (type_map || TypeDefs)[name] = Type::Mapped.new(name)
    In this case, type_map is nil, so this code tries to modify TypeDefs. However, since FFI 1.16.0, TypeDefs is frozen so this exception is raised instead.
  • It seems TypeDefs is frozen due to Make FFI Ractor compatible and allow type retrieval of attached functions+variables #1023, which replaced most use of TypeDefs with custom_typedefs.

My tentative conclusion is that this line should probably use custom_typedefs as well.

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