Skip to content

Commit

Permalink
Fixed race in dtoa [Bug #17612]
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
nobu and ko1 committed Feb 10, 2021
1 parent ad2c7f8 commit 3acc81d
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 3 deletions.
11 changes: 11 additions & 0 deletions bootstraptest/test_ractor.rb
Expand Up @@ -158,6 +158,17 @@
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
Expand Down
13 changes: 10 additions & 3 deletions missing/dtoa.c
Expand Up @@ -526,6 +526,8 @@ typedef struct Bigint Bigint;

static Bigint *freelist[Kmax+1];

#define BLOCKING_BIGINT ((Bigint *)(-1))

static Bigint *
Balloc(int k)
{
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 3acc81d

Please sign in to comment.