summaryrefslogtreecommitdiff
path: root/io_buffer.c
diff options
context:
space:
mode:
authorJohn Hawthorn <john@hawthorn.email>2025-10-02 12:12:26 -0700
committerJohn Hawthorn <john@hawthorn.email>2025-10-02 13:24:00 -0700
commit3cd2407045a67838cf2ab949e5164676b6870958 (patch)
treee3407f7f1e3675767617b882946f186b2e97875f /io_buffer.c
parent7a4f886cc5e7ebf6fece90491cf4a437576d26a6 (diff)
Don't call gc_mark from IO::buffer compact
Previously on our mark_and_move we were calling rb_gc_mark, which isn't safe to call at compaction time. Co-authored-by: Luke Gruber <luke.gru@gmail.com>
Diffstat (limited to 'io_buffer.c')
-rw-r--r--io_buffer.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/io_buffer.c b/io_buffer.c
index 96f13c364a..87e392b791 100644
--- a/io_buffer.c
+++ b/io_buffer.c
@@ -273,7 +273,7 @@ io_buffer_free(struct rb_io_buffer *buffer)
}
static void
-rb_io_buffer_type_mark_and_move(void *_buffer)
+rb_io_buffer_type_mark(void *_buffer)
{
struct rb_io_buffer *buffer = _buffer;
if (buffer->source != Qnil) {
@@ -282,7 +282,21 @@ rb_io_buffer_type_mark_and_move(void *_buffer)
// which can be otherwise moved by GC compaction.
rb_gc_mark(buffer->source);
} else {
- rb_gc_mark_and_move(&buffer->source);
+ rb_gc_mark_movable(buffer->source);
+ }
+ }
+}
+
+static void
+rb_io_buffer_type_compact(void *_buffer)
+{
+ struct rb_io_buffer *buffer = _buffer;
+ if (buffer->source != Qnil) {
+ if (RB_TYPE_P(buffer->source, T_STRING)) {
+ // The `source` String has to be pinned, because the `base` may point to the embedded String content,
+ // which can be otherwise moved by GC compaction.
+ } else {
+ buffer->source = rb_gc_location(buffer->source);
}
}
}
@@ -311,10 +325,10 @@ rb_io_buffer_type_size(const void *_buffer)
static const rb_data_type_t rb_io_buffer_type = {
.wrap_struct_name = "IO::Buffer",
.function = {
- .dmark = rb_io_buffer_type_mark_and_move,
+ .dmark = rb_io_buffer_type_mark,
.dfree = rb_io_buffer_type_free,
.dsize = rb_io_buffer_type_size,
- .dcompact = rb_io_buffer_type_mark_and_move,
+ .dcompact = rb_io_buffer_type_compact,
},
.data = NULL,
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,