Class: Gem::SafeMarshal::Reader
| Relationships & Source Files | |
| Namespace Children | |
|
Exceptions:
| |
| Inherits: | Object |
| Defined in: | lib/rubygems/safe_marshal/reader.rb |
Constant Summary
-
EMPTY_ARRAY =
private
# File 'lib/rubygems/safe_marshal/reader.rb', line 186Elements::Array.new([].freeze).freeze
-
EMPTY_HASH =
private
# File 'lib/rubygems/safe_marshal/reader.rb', line 223Elements::Hash.new([].freeze).freeze
-
EMPTY_STRING =
private
# File 'lib/rubygems/safe_marshal/reader.rb', line 162Elements::String.new("".b.freeze).freeze
-
MARSHAL_VERSION =
private
# File 'lib/rubygems/safe_marshal/reader.rb', line 47[Marshal::MAJOR_VERSION, Marshal::MINOR_VERSION].map(&:chr).join.freeze
-
STRING_E_SYMBOL =
private
# File 'lib/rubygems/safe_marshal/reader.rb', line 144Elements::Symbol.new("E").freeze
Class Method Summary
- .new(io) ⇒ Reader constructor
Instance Method Summary
- #read!
- #read_array private
- #read_bignum private
- #read_byte private
- #read_bytes(n) private
- #read_class private
- #read_class_or_module private
-
#read_count
private
Reads an element count and validates it against the number of bytes remaining in the input, since each element to be read consumes at least one byte.
- #read_data private
- #read_element private
- #read_extended_object private
- #read_false private
- #read_float private
- #read_hash private
- #read_hash_with_default_value private
- #read_header private
- #read_integer private
- #read_module private
- #read_nil private
- #read_object private
- #read_object_link private
- #read_object_with_ivars private
- #read_regexp private
- #read_string private
- #read_struct private
- #read_symbol private
- #read_symbol_link private
- #read_true private
- #read_user_class private
- #read_user_defined private
- #read_user_marshal private
Constructor Details
.new(io) ⇒ Reader
# File 'lib/rubygems/safe_marshal/reader.rb', line 32
def initialize(io) @io = io @object_links = {} @symbol_links = {} end
Instance Method Details
#read!
# File 'lib/rubygems/safe_marshal/reader.rb', line 38
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
#read_array (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 189
def read_array length = read_count return EMPTY_ARRAY if length == 0 elements = Array.new(length) do read_element end Elements::Array.new(elements) end
#read_bignum (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 263
def read_bignum sign = read_byte data = read_bytes(read_integer * 2) Elements::Bignum.new(sign, data) end
#read_byte (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 63
def read_byte @io.getbyte || raise(EOFError, "Unexpected EOF") end
#read_bytes(n) (private)
# File 'lib/rubygems/safe_marshal/reader.rb', line 55
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 (private)
# File 'lib/rubygems/safe_marshal/reader.rb', line 273
def read_class raise NotImplementedError, "Reading Marshal objects of type class is not implemented" end
#read_class_or_module (private)
# File 'lib/rubygems/safe_marshal/reader.rb', line 281
def read_class_or_module raise NotImplementedError, "Reading Marshal objects of type class_or_module is not implemented" end
#read_count (private)
Reads an element count and validates it against the number of bytes remaining in the input, since each element to be read consumes at least one byte. This prevents allocating huge backing stores for maliciously crafted lengths that could never be satisfied.
# File 'lib/rubygems/safe_marshal/reader.rb', line 103
def read_count count = read_integer raise NegativeLengthError if count < 0 remaining = @io.size - @io.pos raise LengthTooLongError, "expected #{count} elements, but only #{remaining} bytes remain" if count > remaining count end
#read_data (private)
# File 'lib/rubygems/safe_marshal/reader.rb', line 285
def read_data raise NotImplementedError, "Reading Marshal objects of type data is not implemented" end
#read_element (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 111
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 (private)
# File 'lib/rubygems/safe_marshal/reader.rb', line 269
def read_extended_object raise NotImplementedError, "Reading Marshal objects of type extended_object is not implemented" end
#read_false (private)
[ GitHub ]#read_float (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 258
def read_float string = read_bytes(read_integer) Elements::Float.new(string) end
#read_hash (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 226
def read_hash length = read_count 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 (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 235
def read_hash_with_default_value length = read_count pairs = Array.new(length) do [read_element, read_element] end default = read_element Elements::HashWithDefaultValue.new(pairs, default) end
#read_header (private)
# File 'lib/rubygems/safe_marshal/reader.rb', line 50
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 (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 67
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 (private)
# File 'lib/rubygems/safe_marshal/reader.rb', line 277
def read_module raise NotImplementedError, "Reading Marshal objects of type module is not implemented" end
#read_nil (private)
[ GitHub ]#read_object (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 244
def read_object name = read_element object = Elements::Object.new(name) length = read_count ivars = Array.new(length) do [read_element, read_element] end Elements::WithIvars.new(object, ivars) end
#read_object_link (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 218
def read_object_link offset = read_integer @object_links[offset] ||= Elements::ObjectLink.new(offset) end
#read_object_with_ivars (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 198
def read_object_with_ivars object = read_element length = read_count ivars = Array.new(length) do [read_element, read_element] end Elements::WithIvars.new(object, ivars) end
#read_regexp (private)
# File 'lib/rubygems/safe_marshal/reader.rb', line 289
def read_regexp raise NotImplementedError, "Reading Marshal objects of type regexp is not implemented" end
#read_string (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 165
def read_string length = read_integer return EMPTY_STRING if length == 0 str = read_bytes(length) Elements::String.new(str) end
#read_struct (private)
# File 'lib/rubygems/safe_marshal/reader.rb', line 293
def read_struct raise NotImplementedError, "Reading Marshal objects of type struct is not implemented" end
#read_symbol (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 147
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_symbol_link (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 207
def read_symbol_link offset = read_integer @symbol_links[offset] ||= Elements::SymbolLink.new(offset) end
#read_true (private)
[ GitHub ]#read_user_class (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 297
def read_user_class name = read_element wrapped_object = read_element Elements::UserClass.new(name, wrapped_object) end
#read_user_defined (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 180
def read_user_defined name = read_element binary_string = read_bytes(read_integer) Elements::UserDefined.new(name, binary_string) end
#read_user_marshal (private)
[ GitHub ]# File 'lib/rubygems/safe_marshal/reader.rb', line 212
def read_user_marshal name = read_element data = read_element Elements::UserMarshal.new(name, data) end