Skip to content

Commit

Permalink
Fix Marshal.load of multiple Symbols with an explicit encoding
Browse files Browse the repository at this point in the history
* Fixes #1624

(cherry picked from commit c4635fd)
  • Loading branch information
eregon committed Jul 13, 2021
1 parent f1b015d commit 4d1a00d
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Bug fixes:
* Fix `Array#[a, b] = "frozen string literal".freeze` (#2355).
* `rb_funcall()` now releases the C-extension lock (similar to MRI).
* Fix `rb_str_modify_expand` to preserve existing bytes (#2392).
* Fix `Marshal.load` of multiple `Symbols` with an explicit encoding (#1624).

Compatibility:

Expand Down
31 changes: 24 additions & 7 deletions src/main/ruby/truffleruby/core/marshal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,18 @@ def add_object(obj)
end

def add_symlink(obj)
sz = @symlinks.size
sz = @symbols.size
@symbols[sz] = obj
@symlinks[obj.__id__] = sz
end

def reserve_symlink
sz = @symbols.size
@symbols[sz] = nil
sz
end

def assign_reserved_symlink(sz, obj)
@symbols[sz] = obj
@symlinks[obj.__id__] = sz
end
Expand Down Expand Up @@ -848,7 +859,6 @@ def construct_regexp

def construct_struct
name = get_symbol
store_unique_object name

klass = const_lookup name, Class
members = klass.members
Expand All @@ -859,8 +869,7 @@ def construct_struct
construct_integer.times do |i|
slot = get_symbol
unless members[i].intern == slot
raise TypeError, 'struct %s is not compatible (%p for %p)' %
[klass, slot, members[i]]
raise TypeError, "struct #{klass} is not compatible (#{slot.inspect} for #{members[i].inspect})"
end

Primitive.object_hidden_var_set obj, slot, construct
Expand All @@ -872,6 +881,12 @@ def construct_struct
def construct_symbol(ivar_index)
data = get_byte_sequence

# We must use the next @symbols index for the Symbol being constructed.
# However, constructing a Symbol might require to construct the :E or :encoding symbols,
# and those must have a larger index (if they are serialized for the first time),
# to be binary-compatible with CRuby and pass specs. So we reserve the index and assign it later.
idx = reserve_symlink

# A Symbol has no instance variables (it's frozen),
# but we need to know the encoding before building the Symbol
if ivar_index and @has_ivar[ivar_index]
Expand All @@ -881,7 +896,7 @@ def construct_symbol(ivar_index)
end

obj = data.to_sym
store_unique_object obj
assign_reserved_symlink idx, obj

obj
end
Expand Down Expand Up @@ -910,7 +925,6 @@ def construct_user_defined(ivar_index)

def construct_user_marshal
name = get_symbol
store_unique_object name

klass = const_lookup name, Class
obj = klass.allocate
Expand Down Expand Up @@ -976,7 +990,7 @@ def serialize(obj)
raise ArgumentError, 'exceed depth limit' if @depth == 0

# How much depth we have left.
@depth -= 1;
@depth -= 1

if link = find_link(obj)
str = Truffle::Type.binary_string("@#{serialize_integer(link)}")
Expand Down Expand Up @@ -1249,7 +1263,10 @@ def initialize(stream, depth, prc)
if @stream
@byte_array = stream.bytes
end
end

def inspect
"#<Marshal::StringState #{@stream[@consumed..-1].inspect}>"
end

def consume(bytes)
Expand Down

0 comments on commit 4d1a00d

Please sign in to comment.