[ruby/stringio] Fix thread safety of strio_free

(https://github.com/ruby/stringio/pull/223)

Follow up to #222

This refcount previously wasn't thread safe (and shouldn't have been
declared `RUBY_TYPED_THREAD_SAFE_FREE`), but it's easy enough to fix
using ruby/atomic.h (Ruby 3.0+)

https://github.com/ruby/stringio/commit/2825dc3007
This commit is contained in:
John Hawthorn 2026-08-01 00:31:39 -07:00 committed by git
parent 48bf798181
commit 12c1ddef89

View File

@ -31,6 +31,19 @@ STRINGIO_VERSION = "3.2.1.dev";
# define RB_INTEGER_TYPE_P(c) (FIXNUM_P(c) || RB_TYPE_P(c, T_BIGNUM))
#endif
/* strio_free may run on any thread, so the refcount shared by #initialize_copy must be atomic */
#ifdef RUBY_TYPED_THREAD_SAFE_FREE
# include "ruby/atomic.h"
typedef rb_atomic_t strio_refcnt_t;
# define STRIO_REFCNT_INC(ptr) RUBY_ATOMIC_INC((ptr)->count)
# define STRIO_REFCNT_DEC(ptr) (RUBY_ATOMIC_FETCH_SUB((ptr)->count, 1) == 1)
#else
# define RUBY_TYPED_THREAD_SAFE_FREE RUBY_TYPED_FREE_IMMEDIATELY
typedef int strio_refcnt_t;
# define STRIO_REFCNT_INC(ptr) ((void)++(ptr)->count)
# define STRIO_REFCNT_DEC(ptr) (--(ptr)->count <= 0)
#endif
#ifndef RB_PASS_CALLED_KEYWORDS
# define rb_funcallv_kw(recv, mid, arg, argv, kw_splat) rb_funcallv(recv, mid, arg, argv)
# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
@ -63,7 +76,7 @@ struct StringIO {
long pos;
long lineno;
rb_io_mode_t flags;
int count;
strio_refcnt_t count;
};
static struct StringIO *get_strio_for_read(VALUE self);
@ -105,8 +118,8 @@ static void
strio_free(void *p)
{
struct StringIO *ptr = p;
if (--ptr->count <= 0) {
xfree(ptr);
if (STRIO_REFCNT_DEC(ptr)) {
xfree(ptr);
}
}
@ -116,10 +129,6 @@ strio_memsize(const void *p)
return sizeof(struct StringIO);
}
#ifndef RUBY_TYPED_THREAD_SAFE_FREE
#define RUBY_TYPED_THREAD_SAFE_FREE RUBY_TYPED_FREE_IMMEDIATELY
#endif
static const rb_data_type_t strio_data_type = {
"strio",
{
@ -778,7 +787,7 @@ strio_copy(VALUE copy, VALUE orig)
RB_OBJ_WRITTEN(copy, old_string, ptr->string);
RB_FL_UNSET_RAW(copy, STRIO_READWRITE);
RB_FL_SET_RAW(copy, RB_FL_TEST_RAW(orig, STRIO_READWRITE));
++ptr->count;
STRIO_REFCNT_INC(ptr);
return copy;
}