-
-
Notifications
You must be signed in to change notification settings - Fork 942
Closed
Milestone
Description
On Ruby 2.0 (FFI gem), the below code runs without errors. On JRuby it will fail on two accounts:
- A struct by reference (i.e. it’s given a pointer at initialization, memory is not allocated by FFI) will use a VariableLengthArray as field type, where Ruby uses an InlineArray of size 0. VariableLengthArray does not exist in Ruby FFI (I believe?), and while useful is maybe not what one would mean with
[:type, 0]— perhapsnilis a better value than0to coerce into a VariableLengthArray instead of an Array, and always use Array for any integer value? - When FFI allocates the memory, one cannot access the field at all, and I am assuming this is because FFI does not allocate memory for the VariableLengthArray because it does not know how much memory is needed.
Using nil instead of 0 as a signal for a field being of variable length (and not having an explicit size) might break backwards-compatibility, but only on JRuby. Ruby FFI on MRI and Rubinius does not have the VariableLengthArray at all, and always return an Array field.
require "ffi"
class Zero < FFI::Struct
layout dummy: :uint,
pointers: [ :pointer, 0 ]
end
class One < FFI::Struct
layout dummy: :uint,
pointers: [ :pointer, 1 ]
end
fzero = Zero.layout.fields[1]
fone = One.layout.fields[1]
p [fzero, fzero.size] # => StructLayout::Array, size 0
p [fone, fone.size] # => StructLayout::Array, size 8
zero = Zero.new(FFI::Pointer::NULL) # existing pointer
one = One.new(FFI::Pointer::NULL) # existing pointer
p zero[:pointers] # => Struct::InlineArray (MRI), StructLayout::VariableLengthArrayProxy (JRuby)
p zero[:pointers].size # => 0
# ^ fails on JRuby, NoMethodError: undefined method `size' for #<FFI::StructLayout::VariableLengthArrayProxy:0x5edea768>
p one[:pointers] # => Struct::InlineArray (MRI), Struct::ArrayProxy (JRuby)
p one[:pointers].size # => 1
zero = Zero.new # allocate memory
one = One.new # allocate memory
p zero[:pointers]
# ^ fails on JRuby, IndexError: Memory access offset=8 size=1 is out of bounds
# [] at org/jruby/ext/ffi/Struct.java:27
p one[:pointers]Array fields of size 0, instead of being variable length when length is set as 0, are convenient for fields you map over. I’ve defined structs, where the size of the array is defined at runtime (and could be 0), which allows me to write code like this:
class MyStruct < FFI::Struct
layout count: :uint, names: [:pointer, 0]
def initialize(…)
# logic for calculating the *true* layout, runtime, when handed a pointer
super(…, *new_layout)
end
end
MyStruct.new(some_pointer)[:names].map(&:read_string) # => returns [] on MRI and Rubinius, raises an error on JRubyReactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels