mirror of
https://github.com/ruby/ruby.git
synced 2026-08-07 19:38:39 +08:00
IO::Buffer#locked: Release lock even when the block raises (#16180)
IO::Buffer#locked: Release lock even when the block raises/breaks Previously, `IO::Buffer#locked` leaks the lock when the block raises an exception, or breaks. Fixes: [Bug #21882]
This commit is contained in:
parent
126b657bd1
commit
b5ccab2093
Notes:
git
2026-02-20 01:57:18 +00:00
Merged-By: ioquatix <samuel@codeotaku.com>
17
io_buffer.c
17
io_buffer.c
@ -1424,6 +1424,17 @@ rb_io_buffer_try_unlock(VALUE self)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_io_buffer_locked_ensure(VALUE self)
|
||||
{
|
||||
struct rb_io_buffer *buffer = NULL;
|
||||
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
|
||||
|
||||
buffer->flags &= ~RB_IO_BUFFER_LOCKED;
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq: locked { ... }
|
||||
*
|
||||
@ -1466,11 +1477,7 @@ rb_io_buffer_locked(VALUE self)
|
||||
|
||||
buffer->flags |= RB_IO_BUFFER_LOCKED;
|
||||
|
||||
VALUE result = rb_yield(self);
|
||||
|
||||
buffer->flags &= ~RB_IO_BUFFER_LOCKED;
|
||||
|
||||
return result;
|
||||
return rb_ensure(rb_yield, self, rb_io_buffer_locked_ensure, self);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -930,4 +930,34 @@ class TestIOBuffer < Test::Unit::TestCase
|
||||
assert_equal value, round_trip_value, "#{le_type}/#{be_type}: double-swap should restore original value"
|
||||
end
|
||||
end
|
||||
|
||||
class Bug21882 < RuntimeError; end
|
||||
def test_locked_exception
|
||||
buf = IO::Buffer.new(10)
|
||||
assert_raise(Bug21882, '#locked should propagate exception') do
|
||||
buf.locked { raise Bug21882 }
|
||||
end
|
||||
|
||||
# should be unlocked now and can be locked again
|
||||
refute_predicate buf, :locked?
|
||||
buf.locked { }
|
||||
end
|
||||
|
||||
def test_locked_break
|
||||
buf = IO::Buffer.new(10)
|
||||
assert_equal :ok, (buf.locked { break :ok })
|
||||
|
||||
# should be unlocked now and can be locked again
|
||||
refute_predicate buf, :locked?
|
||||
buf.locked { }
|
||||
end
|
||||
|
||||
def test_locked_throw
|
||||
buf = IO::Buffer.new(10)
|
||||
assert_equal :ok, (catch(:bug21882) { buf.locked { throw :bug21882, :ok } })
|
||||
|
||||
# should be unlocked now and can be locked again
|
||||
refute_predicate buf, :locked?
|
||||
buf.locked { }
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user