diff --git a/ext/concurrent-ruby-ext/atomic_fixnum.c b/ext/concurrent-ruby-ext/atomic_fixnum.c index 088874006..2abe9c5f7 100644 --- a/ext/concurrent-ruby-ext/atomic_fixnum.c +++ b/ext/concurrent-ruby-ext/atomic_fixnum.c @@ -73,6 +73,7 @@ VALUE method_atomic_fixnum_update(VALUE self) { for (;;) { old_value = method_atomic_fixnum_value(self); new_value = rb_yield(old_value); + Check_Type(new_value, T_FIXNUM); if (ir_compare_and_set(self, old_value, new_value) == Qtrue) { return new_value; } diff --git a/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb b/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb index 0ca395579..132616b77 100644 --- a/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +++ b/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb @@ -55,7 +55,7 @@ def compare_and_set(expect, update) # @!macro atomic_fixnum_method_update def update synchronize do - @value = yield @value + ns_set(yield @value) end end diff --git a/spec/concurrent/atomic/atomic_fixnum_spec.rb b/spec/concurrent/atomic/atomic_fixnum_spec.rb index 8222bf523..81b8e8bf4 100644 --- a/spec/concurrent/atomic/atomic_fixnum_spec.rb +++ b/spec/concurrent/atomic/atomic_fixnum_spec.rb @@ -152,6 +152,17 @@ atomic = described_class.new(1000) expect(atomic.update { |v| v + 1 }).to eq 1001 end + + it 'rejects a non-integer result without changing the value' do + atomic = described_class.new(1000) + + expect { + atomic.update { 'not an integer' } + }.to(raise_error { |error| + expect(error.class).to be(ArgumentError).or(be(TypeError)) + }) + expect(atomic.value).to eq 1000 + end end end