[Bug][ActiveSupport::Cache, ActiveSupport#delegate_missing_to] instance variables "leaking" externally when caching array of ActiveRecord objects with attachments

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[Bug][ActiveSupport::Cache, ActiveSupport#delegate_missing_to] instance variables "leaking" externally when caching array of ActiveRecord objects with attachments

Aaron Lipman
I've found some buggy behavior when caching & uncaching an array of ActiveRecord objects with ActiveStorage attachments. Here's a truncated code snippet demonstrating the bug:

class User < ActiveRecord::Base
  has_one_attached :avatar
end

users = User.first 5
users.each { |user| user.avatar }
Rails.cache.write "key", users
uncached_users = Rails.cache.read "key"

users[1]
# => :@attachment_changes

users[2]
# => {}

In the above code, every element of the array users is an instance of User. After writing to and reading from the cache, every element of uncached_users should still be an instance of User. However, after reading from the cache, the second and third elements of uncached_users are a symbol and empty hash. Here's a full executable test case: https://gist.github.com/alipman88/12928dfd2f86afacd1af51aeb8ae5194

After some digging, I've determined the underlying cause is a bug in Ruby itself, allowing instance variables to be added or removed during marshallization. (Many of Rails' cache stores use Marshal.load & Marshal.dump to serialize & deserialize objects.) While I'll skip over the specifics, the bug will be corrected in future implementations of Ruby. Here's the ticket on Ruby's issue tracker, for anyone seeking more detail: https://bugs.ruby-lang.org/issues/15968

Although future versions of Ruby will fix the underlying issue by raising a RuntimeError, this won't completely solve the problem: Rails developers may still encounter a somewhat confounding error without an immediately obvious cause.

I've submitted a pull request that fixes this issue by patching the delegate_missing_to extension through which this behavior arises: https://github.com/rails/rails/pull/36623

It's been a couple weeks since I submitted my pull request. Per advice in the Contributing to Ruby on Rails guide, I'm hoping to nudge things along and attract some code reviewers by posting here. I respect that Rails is a volunteer project, and appreciate any feedback when folks are able to provide it.

--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-core/67cac147-cb21-41e1-bbf8-25e1895c8fc0%40googlegroups.com.