summaryrefslogtreecommitdiff
path: root/string.c
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2021-04-12 22:56:15 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2021-04-13 12:05:31 +0900
commit12f7ba5ed4a07855d6a9429aa627211db3655ca7 (patch)
tree348dcc90f0b3d4f08748566d72d6ea9dbb71f979 /string.c
parentdf7efdcb6b7fd4286fe7d1fe853fb679aa6a5120 (diff)
Make String#crypt ractor-safe
Diffstat (limited to 'string.c')
-rw-r--r--string.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/string.c b/string.c
index 80ea96f574..145a153096 100644
--- a/string.c
+++ b/string.c
@@ -9667,6 +9667,42 @@ rb_str_oct(VALUE str)
return rb_str_to_inum(str, -8, FALSE);
}
+#ifndef HAVE_CRYPT_R
+# include "ruby/thread_native.h"
+# include "ruby/atomic.h"
+
+static struct {
+ rb_atomic_t initialized;
+ rb_nativethread_lock_t lock;
+} crypt_mutex;
+
+static void
+crypt_mutex_destroy(void)
+{
+ RUBY_ASSERT_ALWAYS(crypt_mutex.initialized == 1);
+ rb_nativethread_lock_destroy(&crypt_mutex.lock);
+ crypt_mutex.initialized = 0;
+}
+
+static void
+crypt_mutex_initialize(void)
+{
+ rb_atomic_t i;
+ while ((i = RUBY_ATOMIC_CAS(crypt_mutex.initialized, 0, 2)) == 2);
+ switch (i) {
+ case 0:
+ rb_nativethread_lock_initialize(&crypt_mutex.lock);
+ atexit(crypt_mutex_destroy);
+ RUBY_ASSERT(crypt_mutex.initialized == 2);
+ RUBY_ATOMIC_CAS(crypt_mutex.initialized, 2, 1);
+ break;
+ case 1:
+ break;
+ default:
+ rb_bug("crypt_mutex.initialized: %d->%d", i, crypt_mutex.initialized);
+ }
+}
+#endif
/*
* call-seq:
@@ -9737,7 +9773,7 @@ rb_str_crypt(VALUE str, VALUE salt)
# define CRYPT_END() ALLOCV_END(databuf)
#else
extern char *crypt(const char *, const char *);
-# define CRYPT_END() (void)0
+# define CRYPT_END() rb_nativethread_lock_unlock(&crypt_mutex.lock)
#endif
VALUE result;
const char *s, *saltp;
@@ -9770,6 +9806,8 @@ rb_str_crypt(VALUE str, VALUE salt)
# endif
res = crypt_r(s, saltp, data);
#else
+ crypt_mutex_initialize();
+ rb_nativethread_lock_lock(&crypt_mutex.lock);
res = crypt(s, saltp);
#endif
if (!res) {