`io_buffer_not` accessed `buffer->base` directly without validating that the buffer was still live. A slice whose parent had been freed retained its stale base pointer, so calling `~` on it caused a UAF. Use `io_buffer_get_bytes_for_rea...himura467 (Akito Shitara)
`io_buffer_xor` accessed `buffer->base` and `mask_buffer->base` directly without validating that the buffers were still live. A slice whose parent had been freed retained its stale base pointer, so calling `^` on it caused a UAF. Use `i...himura467 (Akito Shitara)
`io_buffer_or` accessed `buffer->base` and `mask_buffer->base` directly without validating that the buffers were still live. A slice whose parent had been freed retained its stale base pointer, so calling `|` on it caused a UAF. Use `io...himura467 (Akito Shitara)
Thank you @Eregon > What do you mean by "undocumented GC behavior"? Isn't it only relying on an object keeping its ivar values alive? That's well documented. Agreed, "undocumented" was imprecise. What I meant is that the relations...himura467 (Akito Shitara)
Thank you @jhawthorn > For what it's worth, I'm unconvinced this existing optimization is paying off (and I intend to remove it from the fstring case, where it definitely isn't). At least in CRuby itself at boot we create ~500 strings...himura467 (Akito Shitara)
Thank you for raising this, it's a good point worth keeping in mind. The zero-copy path only applies to READONLY buffers, and `T_STRING` stored in `buffer->source` is guaranteed to be frozen by the design of `IO::Buffer.for`. Since th...himura467 (Akito Shitara)
> I see. So it's mutable, but Copy-on-Write. If you mutate the string, all the content is copied in a buffer managed by Ruby. Yes, that's correct.himura467 (Akito Shitara)
Thank you @byroot, for pointing out the concern. We are designing this new "external" string to be mutable. Regarding the complexity concern, the mechanism for handling cases where the zero-copy returned string is modified can be imp...himura467 (Akito Shitara)