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]hanazuki (Kasumi Hanazuki)
The block passed to `IO::Buffer#each` can free or resize the receiver (or its parent buffer when the reciver is a slice), which invalidates the memory region being iterated. The next iteration causes use-after-free.
Applied in changeset commit:git|b5ccab2093c9bb19ae8564a935e6fd72ec7354cc. ---------- IO::Buffer#locked: Release lock even when the block raises (#16180) IO::Buffer#locked: Release lock even when the block raises/breaks Previously, `IO...hanazuki (Kasumi Hanazuki)
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]hanazuki (Kasumi Hanazuki)
```ruby # Assume this file is on a very slow device such as NFS. io = File.open('/mnt/slowfs/slow') buf = IO::Buffer.new(100) t1 = Thread.new do buf.locked do sleep 0.5 end buf.free end t2 = Thread.new do b...hanazuki (Kasumi Hanazuki)
`IO::Buffer#locked` should unlock the buffer even after the block raises an exception. ```ruby buf = IO::Buffer.new(100) buf.locked { fail } rescue nil buf.locked { p :ok } # expected to print :ok, but actually raises a LockedErro...hanazuki (Kasumi Hanazuki)
I think @alanwu means the mutable buffer path (IO::Buffer.for w/ block) uses rb_str_locktmp to pin the String's malloc'ed content memory (not RString), while the immutable buffer path (IO::Buffer.for w/o block) utilizes CoW to obtain a f...hanazuki (Kasumi Hanazuki)
Applied in changeset commit:git|8aac19d5987150cf5c45fee73c7a949ca472f488. ---------- io_buffer: Reimplement dcompact for IO::Buffer The `source` field in IO::Buffer can have a String or an IO::Buffer object, if not nil. - When the `so...hanazuki (Kasumi Hanazuki)