class Gem::SafeMarshal::Reader

Constants

EMPTY_ARRAY
EMPTY_HASH
EMPTY_STRING
MARSHAL_VERSION

profiling bundle install –full-index shows that offset 6 is by far the most common object link, so we special case it to avoid allocating a new object a third of the time. the following are all the object links that appear more than 10000 times in my profiling

STRING_E_SYMBOL

Public Class Methods

new(io) click to toggle source
# File rubygems/safe_marshal/reader.rb, line 29
def initialize(io)
  @io = io
end

Public Instance Methods

read!() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 33
def read!
  read_header
  root = read_element
  raise UnconsumedBytesError, "expected EOF, got #{@io.read(10).inspect}... after top-level element #{root.class}" unless @io.eof?
  root
end

Private Instance Methods

read_array() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 172
def read_array
  length = read_integer
  return EMPTY_ARRAY if length == 0
  raise NegativeLengthError if length < 0
  elements = Array.new(length) do
    read_element
  end
  Elements::Array.new(elements)
end
read_bignum() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 284
def read_bignum
  sign = read_byte
  data = read_bytes(read_integer * 2)
  Elements::Bignum.new(sign, data)
end
read_byte() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 58
def read_byte
  @io.getbyte || raise(EOFError, "Unexpected EOF")
end
read_bytes(n) click to toggle source
# File rubygems/safe_marshal/reader.rb, line 50
def read_bytes(n)
  raise NegativeLengthError if n < 0
  str = @io.read(n)
  raise EOFError, "expected #{n} bytes, got EOF" if str.nil?
  raise DataTooShortError, "expected #{n} bytes, got #{str.inspect}" unless str.bytesize == n
  str
end
read_class() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 294
def read_class
  raise NotImplementedError, "Reading Marshal objects of type class is not implemented"
end
read_class_or_module() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 302
def read_class_or_module
  raise NotImplementedError, "Reading Marshal objects of type class_or_module is not implemented"
end
read_data() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 306
def read_data
  raise NotImplementedError, "Reading Marshal objects of type data is not implemented"
end
read_element() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 94
def read_element
  type = read_byte
  case type
  when 34 then read_string # ?"
  when 48 then read_nil # ?0
  when 58 then read_symbol # ?:
  when 59 then read_symbol_link # ?;
  when 64 then read_object_link # ?@
  when 70 then read_false # ?F
  when 73 then read_object_with_ivars # ?I
  when 84 then read_true # ?T
  when 85 then read_user_marshal # ?U
  when 91 then read_array # ?[
  when 102 then read_float # ?f
  when 105 then Elements::Integer.new(read_integer) # ?i
  when 108 then read_bignum # ?l
  when 111 then read_object # ?o
  when 117 then read_user_defined # ?u
  when 123 then read_hash # ?{
  when 125 then read_hash_with_default_value # ?}
  when 101 then read_extended_object # ?e
  when 99 then read_class # ?c
  when 109 then read_module # ?m
  when 77 then read_class_or_module # ?M
  when 100 then read_data # ?d
  when 47 then read_regexp # ?/
  when 83 then read_struct # ?S
  when 67 then read_user_class # ?C
  else
    raise Error, "Unknown marshal type discriminator #{type.chr.inspect} (#{type})"
  end
end
read_extended_object() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 290
def read_extended_object
  raise NotImplementedError, "Reading Marshal objects of type extended_object is not implemented"
end
read_false() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 159
def read_false
  Elements::False::FALSE
end
read_float() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 279
def read_float
  string = read_bytes(read_integer)
  Elements::Float.new(string)
end
read_hash() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 245
def read_hash
  length = read_integer
  return EMPTY_HASH if length == 0
  pairs = Array.new(length) do
    [read_element, read_element]
  end
  Elements::Hash.new(pairs)
end
read_hash_with_default_value() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 254
def read_hash_with_default_value
  length = read_integer
  raise NegativeLengthError if length < 0
  pairs = Array.new(length) do
    [read_element, read_element]
  end
  default = read_element
  Elements::HashWithDefaultValue.new(pairs, default)
end
read_header() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 45
def read_header
  v = @io.read(2)
  raise UnsupportedVersionError, "Unsupported marshal version #{v.bytes.map(&:ord).join(".")}, expected #{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}" unless v == MARSHAL_VERSION
end
read_integer() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 62
def read_integer
  b = read_byte

  case b
  when 0x00
    0
  when 0x01
    read_byte
  when 0x02
    read_byte | (read_byte << 8)
  when 0x03
    read_byte | (read_byte << 8) | (read_byte << 16)
  when 0x04
    read_byte | (read_byte << 8) | (read_byte << 16) | (read_byte << 24)
  when 0xFC
    read_byte | (read_byte << 8) | (read_byte << 16) | (read_byte << 24) | -0x100000000
  when 0xFD
    read_byte | (read_byte << 8) | (read_byte << 16) | -0x1000000
  when 0xFE
    read_byte | (read_byte << 8) | -0x10000
  when 0xFF
    read_byte | -0x100
  else
    signed = (b ^ 128) - 128
    if b >= 128
      signed + 5
    else
      signed - 5
    end
  end
end
read_module() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 298
def read_module
  raise NotImplementedError, "Reading Marshal objects of type module is not implemented"
end
read_nil() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 275
def read_nil
  Elements::Nil::NIL
end
read_object() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 264
def read_object
  name = read_element
  object = Elements::Object.new(name)
  length = read_integer
  raise NegativeLengthError if length < 0
  ivars = Array.new(length) do
    [read_element, read_element]
  end
  Elements::WithIvars.new(object, ivars)
end
read_object_with_ivars() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 182
def read_object_with_ivars
  object = read_element
  length = read_integer
  raise NegativeLengthError if length < 0
  ivars = Array.new(length) do
    [read_element, read_element]
  end
  Elements::WithIvars.new(object, ivars)
end
read_regexp() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 310
def read_regexp
  raise NotImplementedError, "Reading Marshal objects of type regexp is not implemented"
end
read_string() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 148
def read_string
  length = read_integer
  return EMPTY_STRING if length == 0
  str = read_bytes(length)
  Elements::String.new(str)
end
read_struct() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 314
def read_struct
  raise NotImplementedError, "Reading Marshal objects of type struct is not implemented"
end
read_symbol() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 130
def read_symbol
  len = read_integer
  if len == 1
    byte = read_byte
    if byte == 69 # ?E
      STRING_E_SYMBOL
    else
      Elements::Symbol.new(byte.chr)
    end
  else
    name = read_bytes(len)
    Elements::Symbol.new(name)
  end
end
read_true() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 155
def read_true
  Elements::True::TRUE
end
read_user_class() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 318
def read_user_class
  name = read_element
  wrapped_object = read_element
  Elements::UserClass.new(name, wrapped_object)
end
read_user_defined() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 163
def read_user_defined
  name = read_element
  binary_string = read_bytes(read_integer)
  Elements::UserDefined.new(name, binary_string)
end
read_user_marshal() click to toggle source
# File rubygems/safe_marshal/reader.rb, line 197
def read_user_marshal
  name = read_element
  data = read_element
  Elements::UserMarshal.new(name, data)
end