Avoid infinite recursion when bad values are passed to tz aware fields

We had previously updated this to attempt to map over whatever was
passed in, so that additional types like range and array could benefit
from this behavior without the time zone converter having to deal with
every known type.

However, the default behavior of a type is to just yield the given value
to `map`, which means that if we don't actually know how to handle a
value, we'll just recurse infinitely. Since both uses of `map` in this
case occur in cases where we know receiving the same object will
recurse, we can just break on reference equality.

Fixes #23241.
This commit is contained in:
Sean Griffin 2016-02-02 09:15:47 -07:00
parent f7775c74d0
commit 5bb26008ce
2 changed files with 19 additions and 2 deletions

@ -20,7 +20,7 @@ def cast(value)
nil
end
else
map(super) { |t| cast(t) }
map_avoiding_infinite_recursion(super) { |v| cast(v) }
end
end
@ -34,13 +34,23 @@ def convert_time_to_time_zone(value)
elsif value.is_a?(::Float)
value
else
map(value) { |v| convert_time_to_time_zone(v) }
map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
end
end
def set_time_zone_without_conversion(value)
::Time.zone.local_to_utc(value).in_time_zone
end
def map_avoiding_infinite_recursion(value)
map(value) do |v|
if value.equal?(v)
nil
else
yield(value)
end
end
end
end
extend ActiveSupport::Concern

@ -714,6 +714,13 @@ def test_removing_time_zone_aware_types
end
end
def test_time_zone_aware_attributes_dont_recurse_infinitely_on_invalid_values
in_time_zone "Pacific Time (US & Canada)" do
record = @target.new(bonus_time: [])
assert_equal nil, record.bonus_time
end
end
def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
Topic.skip_time_zone_conversion_for_attributes = [:field_a]
Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]