[前][次][番号順一覧][スレッド一覧]

ruby-changes:65217

From: Nobuyoshi <ko1@a...>
Date: Wed, 10 Feb 2021 19:45:01 +0900 (JST)
Subject: [ruby-changes:65217] 3acc81d9e4 (master): Fixed race in dtoa [Bug #17612]

https://git.ruby-lang.org/ruby.git/commit/?id=3acc81d9e4

From 3acc81d9e41b18380b9e0168fe2b5e5e0c727256 Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Wed, 10 Feb 2021 15:24:23 +0900
Subject: Fixed race in dtoa [Bug #17612]

Fixed the race condition when replacing `freelist` entry with its
chained next element.  At acquiring an entry, hold the entry once
with the special value, then release by replacing it with the next
element again after acquired.  If another thread is holding the
same entry at that time, spinning until the entry gets released.

Co-Authored-By: Koichi Sasada <ko1@a...>
---
 bootstraptest/test_ractor.rb | 11 +++++++++++
 missing/dtoa.c               | 13 ++++++++++---
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index b32a790..f1c3197 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -158,6 +158,17 @@ assert_equal '[[:e1, 1], [:e2, 2]]', %q{ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_ractor.rb#L158
   a #
 }
 
+# dtoa race condition
+assert_equal '[:ok, :ok, :ok]', %q{
+  n = 3
+  n.times.map{
+    Ractor.new{
+      10_000.times{ rand.to_s }
+      :ok
+    }
+  }.map(&:take)
+}
+
 ###
 ###
 # Ractor still has several memory corruption so skip huge number of tests
diff --git a/missing/dtoa.c b/missing/dtoa.c
index 41b0a22..a940eab 100644
--- a/missing/dtoa.c
+++ b/missing/dtoa.c
@@ -526,6 +526,8 @@ typedef struct Bigint Bigint; https://github.com/ruby/ruby/blob/trunk/missing/dtoa.c#L526
 
 static Bigint *freelist[Kmax+1];
 
+#define BLOCKING_BIGINT ((Bigint *)(-1))
+
 static Bigint *
 Balloc(int k)
 {
@@ -541,8 +543,10 @@ Balloc(int k) https://github.com/ruby/ruby/blob/trunk/missing/dtoa.c#L543
         rv = freelist[k];
         while (rv) {
             Bigint *rvn = rv;
-            rv = ATOMIC_PTR_CAS(freelist[k], rv, rv->next);
-            if (LIKELY(rvn == rv)) {
+            rv = ATOMIC_PTR_CAS(freelist[k], rv, BLOCKING_BIGINT);
+            if (LIKELY(rv != BLOCKING_BIGINT && rvn == rv)) {
+                rvn = ATOMIC_PTR_CAS(freelist[k], BLOCKING_BIGINT, rv->next);
+                assert(rvn == BLOCKING_BIGINT);
                 ASSUME(rv);
                 break;
             }
@@ -589,7 +593,10 @@ Bfree(Bigint *v) https://github.com/ruby/ruby/blob/trunk/missing/dtoa.c#L593
         }
         ACQUIRE_DTOA_LOCK(0);
         do {
-            vn = v->next = freelist[v->k];
+            do {
+                vn = ATOMIC_PTR_CAS(freelist[v->k], 0, 0);
+            } while (UNLIKELY(vn == BLOCKING_BIGINT));
+            v->next = vn;
         } while (UNLIKELY(ATOMIC_PTR_CAS(freelist[v->k], vn, v) != vn));
         FREE_DTOA_LOCK(0);
     }
-- 
cgit v1.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]