Ruby marshal on a string differs from marshal on a symbol converted to a string

Viewed 130

In both of these cases:

a = Marshal.dump(:rent_active_on.to_s)
b = Marshal.dump('rent_active_on')

a = Marshal.dump(String(:rent_active_on))
b = Marshal.dump(String('rent_active_on'))

a is not equal to b. The end values are ALMOST the same:

 > a = Marshal.dump(:rent_active_on.to_s)
 => "\x04\bI\"\x13rent_active_on\x06:\x06EF" 
 > b = Marshal.dump('rent_active_on')
 => "\x04\bI\"\x13rent_active_on\x06:\x06ET"

The difference is the very last character. The 'F' vs the 'T'. I can't find any way to make them yield the same result. I'm totally confused... what's going on here?

Using Ruby 2.6.1

2 Answers

Somehow Marshal.dump(:rent_active_on.to_s) doesn't produce the same output as Marshal.dump('rent_active_on'), but Marshal.dump("#{:rent_active_on}") does, try interpolating instead:

Marshal.dump("#{:rent_active_on}") # "\x04\bI\"\x13rent_active_on\x06:\x06ET"
Marshal.dump('rent_active_on')     # "\x04\bI\"\x13rent_active_on\x06:\x06ET"

Or you could instead use symbols:

Marshal.dump(:rent_active_on)         # "\x04\b:\x13rent_active_on"
Marshal.dump('rent_active_on'.to_sym) # "\x04\b:\x13rent_active_on"

This seems to be an encoding issue. Either forcing the encoding:

a = Marshal.dump(:rent_active_on.to_s.encode('UTF-8'))
b = Marshal.dump('rent_active_on'.encode('UTF-8'))
a == b # true

Or interpolate:

a = Marshal.dump("#{:rent_active_on}")
b = Marshal.dump('rent_active_on')
a == b # true

If your editor is using, say, ASCII encoding then your symbols will be ASCII encoded. If your system locale is using UTF8, your strings will be encoded in UTF8.

So unless your editor's encoding and your system's encoding are the same this will happen. We tested it on a few systems ranging from ruby 2.5.5 to 2.7.1, and it only worked on a 2.7.0 machine that was set up to always use UTF8 (according to the system's admin)

Generally you don't want to count on binary encoding of an object to be in any way predictable - bytecode changes all the time, locale settings can mess with it, etc. That looks like what's happening here.

Related