mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Prevent Marshal.load
from looping infinitely
Fix a bug in `Marshal.load` that caused it to loop indefinitely when trying to autoload a constant that resolved to a different name. This could occur when marshalling an ActiveRecord 4.0 object (e.g. into memcached) and then trying to unmarshal it with Rails 4.2. The marshalled payload contains a reference to `ActiveRecord::ConnectionAdapters::Mysql2Adapter::Column`, which in Rails 4.2 resolves to `ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::Column`.
This commit is contained in:
parent
a101115d5b
commit
aa0fad5148
3 changed files with 20 additions and 1 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
* Prevent `Marshal.load` from looping infinitely when trying to autoload a constant
|
||||||
|
which resolves to a different name.
|
||||||
|
|
||||||
|
*Olek Janiszewski*
|
||||||
|
|
||||||
* Deprecate `Module.local_constants`. Please use `Module.constants(false)` instead.
|
* Deprecate `Module.local_constants`. Please use `Module.constants(false)` instead.
|
||||||
|
|
||||||
*Yuichiro Kaneko*
|
*Yuichiro Kaneko*
|
||||||
|
|
|
@ -5,7 +5,10 @@ module ActiveSupport
|
||||||
rescue ArgumentError, NameError => exc
|
rescue ArgumentError, NameError => exc
|
||||||
if exc.message.match(%r|undefined class/module (.+)|)
|
if exc.message.match(%r|undefined class/module (.+)|)
|
||||||
# try loading the class/module
|
# try loading the class/module
|
||||||
$1.constantize
|
loaded = $1.constantize
|
||||||
|
|
||||||
|
raise unless $1 == loaded.name
|
||||||
|
|
||||||
# if it is an IO we need to go back to read the object
|
# if it is an IO we need to go back to read the object
|
||||||
source.rewind if source.respond_to?(:rewind)
|
source.rewind if source.respond_to?(:rewind)
|
||||||
retry
|
retry
|
||||||
|
|
|
@ -64,6 +64,17 @@ class MarshalTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "when one constant resolves to another" do
|
||||||
|
class Parent; C = Class.new; end
|
||||||
|
class Child < Parent; C = Class.new; end
|
||||||
|
|
||||||
|
dump = Marshal.dump(Child::C.new)
|
||||||
|
|
||||||
|
Child.send(:remove_const, :C)
|
||||||
|
|
||||||
|
assert_raise(ArgumentError) { Marshal.load(dump) }
|
||||||
|
end
|
||||||
|
|
||||||
test "that a real missing class is causing an exception" do
|
test "that a real missing class is causing an exception" do
|
||||||
dumped = nil
|
dumped = nil
|
||||||
with_autoloading_fixtures do
|
with_autoloading_fixtures do
|
||||||
|
|
Loading…
Reference in a new issue