If you take another look at RString, you’ll see that the next block of data is a union. Depending on the size of the string, this union either represents another struct that contains the length of the string, and a pointer to the string value itself, or an embedded character array containing the string value. What I’ve learned while using Fiddle with strings is that strings of a low length are stored directly within the string object itself and its size calculated according. Let’s test this:

EMBEDDED_LENGTH = (Fiddle::SIZEOF_LONG*3)/Fiddle::SIZEOF_CHAR — 1

str_value_data = str_ptr[Fiddle::SIZEOF_LONG*2, EMBEDDED_LENGTH]

=> “Hello world!\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

Or for a bigger string, let’s get the string size according to where it is in the RString object:

str = “hello world!” * 20

# … get the str pointer like we did before

str_size_data = str_ptr[Fiddle::SIZEOF_LONG*2, Fiddle::SIZEOF_LONG]

str_size = str_size_data.unpack(“Q”)

str_size == str.size

=> true

And the value:

str_value_ptr_int = str_ptr[Fiddle::SIZEOF_LONG*3, Fiddle::SIZEOF_LONG]

str_value_data = Fiddle::Pointer.new str_value_ptr_int

str_value_ptr_int = str_value_data.unpack(“Q”)[0]

str_value_ptr = Fiddle::Pointer.new str_value_ptr_int

str_value_ptr.to_s == str

=> true

This is incredibly cool, and suffice to say you can gain some powerful insight into the internals of Ruby by using Ruby itself. What if we changed the value of the size?

str_ptr[Fiddle::SIZEOF_LONG*2, Fiddle::SIZEOF_LONG] = [10].pack(“Q”)

str.size == 10

=> true

p str

=> “hello worl”

Or what if we changed the class of the object?

fixnum_class_ptr_data = [Fixnum.object_id << 1].pack(“Q”)

str_ptr[Fiddle::SIZEOF_LONG, Fiddle::SIZEOF_LONG] = fixnum_class_ptr_data

str.class == Fixnum

=> true

Pretty awesome if you ask me.