Skip to content

Commit

Permalink
Treat all deserialization errors as UnmarshalError
Browse files Browse the repository at this point in the history
  • Loading branch information
olleolleolle committed Aug 11, 2024
1 parent 6a781c8 commit b0f2e61
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 92 deletions.
46 changes: 4 additions & 42 deletions lib/dalli/protocol/value_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,55 +33,17 @@ def store(value, req_options, bitflags)
[store_value, bitflags]
end

# TODO: Some of these error messages need to be validated. It's not obvious
# that all of them are actually generated by the invoked code
# in current systems
# rubocop:disable Layout/LineLength
TYPE_ERR_REGEXP = %r{needs to have method `_load'|exception class/object expected|instance of IO needed|incompatible marshal file format}.freeze
ARGUMENT_ERR_REGEXP = /undefined class|marshal data too short/.freeze
NAME_ERR_STR = 'uninitialized constant'
# rubocop:enable Layout/LineLength

def retrieve(value, bitflags) # rubocop:disable Metrics/MethodLength
def retrieve(value, bitflags)
serialized = (bitflags & FLAG_SERIALIZED) != 0
if serialized
if serializer.is_a?(Marshal)
begin
serializer.load(value)
rescue StandardError => e
raise UnmarshalError, "Unable to unmarshal value: #{e.message}"
end
else
# Use Dalli's existing exception filtering for deserialization when not using Marshal to serialize.
begin
serializer.load(value)
rescue StandardError => e
raise UnmarshalError, "Unable to unmarshal value: #{e.message}"
end
else
value
end
rescue TypeError => e
filter_type_error(e)
rescue ArgumentError => e
filter_argument_error(e)
rescue NameError => e
filter_name_error(e)
end

def filter_type_error(err)
raise err unless TYPE_ERR_REGEXP.match?(err.message)

raise UnmarshalError, "Unable to unmarshal value: #{err.message}"
end

def filter_argument_error(err)
raise err unless ARGUMENT_ERR_REGEXP.match?(err.message)

raise UnmarshalError, "Unable to unmarshal value: #{err.message}"
end

def filter_name_error(err)
raise err unless err.message.include?(NAME_ERR_STR)

raise UnmarshalError, "Unable to unmarshal value: #{err.message}"
end

def serializer
Expand Down
51 changes: 1 addition & 50 deletions test/protocol/test_value_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@

describe 'when the bitflags specify serialization' do
it 'should deserialize the value' do
serializer.expect :is_a?, true, [Marshal]
serializer.expect :load, deserialized_dummy, [raw_value]
bitflags = rand(32)
bitflags |= 0x1
Expand Down Expand Up @@ -231,22 +230,6 @@
end
end

describe 'when deserialization raises a TypeError with a non-matching message' do
let(:error_message) { SecureRandom.hex(10) }
let(:serializer) { Marshal }

it 're-raises TypeError' do
error = ->(_arg) { raise TypeError, error_message }
exception = serializer.stub :load, error do
assert_raises TypeError do
vs.retrieve(raw_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end
end

assert_equal error_message, exception.message
end
end

describe 'when deserialization raises a NameError for an uninitialized constant' do
let(:error_message) { 'uninitialized constant Ddd' }
let(:serializer) { Marshal }
Expand All @@ -264,22 +247,6 @@
end
end

describe 'when deserialization raises a NameError with a non-matching message' do
let(:error_message) { SecureRandom.hex(10) }
let(:serializer) { Marshal }

it 're-raises NameError' do
error = ->(_arg) { raise NameError, error_message }
exception = serializer.stub :load, error do
assert_raises NameError do
vs.retrieve(raw_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end
end

assert exception.message.start_with?(error_message)
end
end

describe 'when deserialization raises an ArgumentError for an undefined class' do
let(:error_message) { 'undefined class/module NonexistentClass' }
let(:serializer) { Marshal }
Expand Down Expand Up @@ -308,22 +275,6 @@
end
end

describe 'when deserialization raises an ArgumentError with a non-matching message' do
let(:error_message) { SecureRandom.hex(10) }
let(:serializer) { Marshal }

it 're-raises ArgumentError' do
error = ->(_arg) { raise ArgumentError, error_message }
exception = serializer.stub :load, error do
assert_raises ArgumentError do
vs.retrieve(raw_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end
end

assert_equal exception.message, error_message
end
end

describe 'when using the default serializer' do
let(:deserialized_value) { SecureRandom.hex(1024) }
let(:serialized_value) { Marshal.dump(deserialized_value) }
Expand All @@ -335,7 +286,7 @@
deserialized_value
end

it 'raises UnmarshalError for non-seriaized data' do
it 'raises UnmarshalError for non-serialized data' do
assert_raises Dalli::UnmarshalError do
vs.retrieve(:not_serialized_value, Dalli::Protocol::ValueSerializer::FLAG_SERIALIZED)
end
Expand Down

0 comments on commit b0f2e61

Please sign in to comment.