1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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@atdot.net>
This commit is contained in:
Nobuyoshi Nakada 2021-02-10 15:24:23 +09:00
parent ad2c7f8a1e
commit 3acc81d9e4
Notes: git 2021-02-10 19:45:09 +09:00
2 changed files with 21 additions and 3 deletions

View file

@ -158,6 +158,17 @@ assert_equal '[[:e1, 1], [:e2, 2]]', %q{
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

View file

@ -526,6 +526,8 @@ typedef struct Bigint Bigint;
static Bigint *freelist[Kmax+1];
#define BLOCKING_BIGINT ((Bigint *)(-1))
static Bigint *
Balloc(int k)
{
@ -541,8 +543,10 @@ Balloc(int k)
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)
}
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);
}