summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNARUSE, Yui <naruse@airemix.jp>2021-03-13 05:11:30 +0900
committerNARUSE, Yui <naruse@airemix.jp>2021-03-13 05:11:30 +0900
commit6bf32cbed8f3fd0b73b99737d671f833c594d800 (patch)
tree8386c8baaf64923af62e953cf000e1bcea4f6ba2
parent7b122b8af86c155eb23e8cad463cdf2c0bfc1d77 (diff)
merge revision(s) 63abb5c227e5c20d18d0debf699251da93ca64b5,34d02631e71209b12abb69d0114601027e485bc9,2adbf01ae14c0a4cf190b7c969b91726966a0e0f,3acc81d9e41b18380b9e0168fe2b5e5e0c727256: [Backport #17612]
dtoa.c: make compilable independently Except for `-Dxmalloc=malloc -Dxfree=free`. --- missing/dtoa.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) dtoa.c: constified clang seems to locate never modified local data in the const segment implicitly. --- missing/dtoa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) dtoa.c: make thread-safe by using atomic CAS --- common.mk | 2 ++ missing/dtoa.c | 75 ++++++++++++++++++++++++++++++++++++++++++---------------- util.c | 1 + 3 files changed, 57 insertions(+), 21 deletions(-) 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> --- bootstraptest/test_ractor.rb | 11 +++++++++++ missing/dtoa.c | 13 ++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-)
-rw-r--r--bootstraptest/test_ractor.rb11
-rw-r--r--common.mk2
-rw-r--r--missing/dtoa.c108
-rw-r--r--util.c1
-rw-r--r--version.h2
5 files changed, 95 insertions, 29 deletions
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index 878b846487..fd698fa4d7 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -176,6 +176,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
diff --git a/common.mk b/common.mk
index 763305082d..594c165ffd 100644
--- a/common.mk
+++ b/common.mk
@@ -14800,6 +14800,7 @@ util.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
util.$(OBJEXT): $(top_srcdir)/internal/util.h
util.$(OBJEXT): $(top_srcdir)/internal/warnings.h
util.$(OBJEXT): {$(VPATH)}assert.h
+util.$(OBJEXT): {$(VPATH)}atomic.h
util.$(OBJEXT): {$(VPATH)}backward/2/assume.h
util.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
util.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -14955,6 +14956,7 @@ util.$(OBJEXT): {$(VPATH)}internal/variable.h
util.$(OBJEXT): {$(VPATH)}internal/warning_push.h
util.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
util.$(OBJEXT): {$(VPATH)}missing.h
+util.$(OBJEXT): {$(VPATH)}ruby_atomic.h
util.$(OBJEXT): {$(VPATH)}st.h
util.$(OBJEXT): {$(VPATH)}subst.h
util.$(OBJEXT): {$(VPATH)}util.c
diff --git a/missing/dtoa.c b/missing/dtoa.c
index cbee13ee81..a940eabd91 100644
--- a/missing/dtoa.c
+++ b/missing/dtoa.c
@@ -183,12 +183,16 @@
#undef Long
#undef ULong
-#if SIZEOF_INT == 4
+#include <limits.h>
+
+#if (INT_MAX >> 30) && !(INT_MAX >> 31)
#define Long int
#define ULong unsigned int
-#elif SIZEOF_LONG == 4
+#elif (LONG_MAX >> 30) && !(LONG_MAX >> 31)
#define Long long int
#define ULong unsigned long int
+#else
+#error No 32bit integer
#endif
#if HAVE_LONG_LONG
@@ -202,6 +206,11 @@
#define Bug(x) {fprintf(stderr, "%s\n", (x)); exit(EXIT_FAILURE);}
#endif
+#ifndef ISDIGIT
+#include <ctype.h>
+#define ISDIGIT(c) isdigit(c)
+#endif
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
@@ -219,6 +228,9 @@ extern void FREE(void*);
#else
#define FREE xfree
#endif
+#ifndef NO_SANITIZE
+#define NO_SANITIZE(x, y) y
+#endif
#ifndef Omit_Private_Memory
#ifndef PRIVATE_MEM
@@ -280,7 +292,7 @@ extern "C" {
#endif
#ifndef hexdigit
-static const char hexdigits[] = "0123456789abcdef0123456789ABCDEF";
+static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
#endif
#if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + defined(IBM) != 1
@@ -489,6 +501,19 @@ extern double rnd_prod(double, double), rnd_quot(double, double);
#define FREE_DTOA_LOCK(n) /*unused right now*/
#endif
+#ifndef ATOMIC_PTR_CAS
+#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (old))
+#endif
+#ifndef LIKELY
+#define LIKELY(x) (x)
+#endif
+#ifndef UNLIKELY
+#define UNLIKELY(x) (x)
+#endif
+#ifndef ASSUME
+#define ASSUME(x) (void)(x)
+#endif
+
#define Kmax 15
struct Bigint {
@@ -501,6 +526,8 @@ typedef struct Bigint Bigint;
static Bigint *freelist[Kmax+1];
+#define BLOCKING_BIGINT ((Bigint *)(-1))
+
static Bigint *
Balloc(int k)
{
@@ -510,22 +537,41 @@ Balloc(int k)
size_t len;
#endif
+ rv = 0;
ACQUIRE_DTOA_LOCK(0);
- if (k <= Kmax && (rv = freelist[k]) != 0) {
- freelist[k] = rv->next;
+ if (k <= Kmax) {
+ rv = freelist[k];
+ while (rv) {
+ Bigint *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;
+ }
+ }
}
- else {
+ if (!rv) {
x = 1 << k;
#ifdef Omit_Private_Memory
rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
#else
len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
/sizeof(double);
- if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
- rv = (Bigint*)pmem_next;
- pmem_next += len;
+ if (k <= Kmax) {
+ double *pnext = pmem_next;
+ while (pnext - private_mem + len <= PRIVATE_mem) {
+ double *p = pnext;
+ pnext = ATOMIC_PTR_CAS(pmem_next, pnext, pnext + len);
+ if (LIKELY(p == pnext)) {
+ rv = (Bigint*)pnext;
+ ASSUME(rv);
+ break;
+ }
+ }
}
- else
+ if (!rv)
rv = (Bigint*)MALLOC(len*sizeof(double));
#endif
rv->k = k;
@@ -539,14 +585,19 @@ Balloc(int k)
static void
Bfree(Bigint *v)
{
+ Bigint *vn;
if (v) {
if (v->k > Kmax) {
FREE(v);
return;
}
ACQUIRE_DTOA_LOCK(0);
- v->next = freelist[v->k];
- freelist[v->k] = v;
+ do {
+ 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);
}
}
@@ -829,8 +880,9 @@ static Bigint *
pow5mult(Bigint *b, int k)
{
Bigint *b1, *p5, *p51;
+ Bigint *p5tmp;
int i;
- static int p05[3] = { 5, 25, 125 };
+ static const int p05[3] = { 5, 25, 125 };
if ((i = k & 3) != 0)
b = multadd(b, p05[i-1], 0);
@@ -839,17 +891,17 @@ pow5mult(Bigint *b, int k)
return b;
if (!(p5 = p5s)) {
/* first time */
-#ifdef MULTIPLE_THREADS
ACQUIRE_DTOA_LOCK(1);
if (!(p5 = p5s)) {
- p5 = p5s = i2b(625);
+ p5 = i2b(625);
p5->next = 0;
+ p5tmp = ATOMIC_PTR_CAS(p5s, NULL, p5);
+ if (UNLIKELY(p5tmp)) {
+ Bfree(p5);
+ p5 = p5tmp;
+ }
}
FREE_DTOA_LOCK(1);
-#else
- p5 = p5s = i2b(625);
- p5->next = 0;
-#endif
}
for (;;) {
if (k & 1) {
@@ -860,17 +912,17 @@ pow5mult(Bigint *b, int k)
if (!(k >>= 1))
break;
if (!(p51 = p5->next)) {
-#ifdef MULTIPLE_THREADS
ACQUIRE_DTOA_LOCK(1);
if (!(p51 = p5->next)) {
- p51 = p5->next = mult(p5,p5);
+ p51 = mult(p5,p5);
p51->next = 0;
+ p5tmp = ATOMIC_PTR_CAS(p5->next, NULL, p51);
+ if (UNLIKELY(p5tmp)) {
+ Bfree(p51);
+ p51 = p5tmp;
+ }
}
FREE_DTOA_LOCK(1);
-#else
- p51 = p5->next = mult(p5,p5);
- p51->next = 0;
-#endif
}
p5 = p51;
}
@@ -2520,10 +2572,10 @@ static char *dtoa_result;
static char *
rv_alloc(int i)
{
- return dtoa_result = xmalloc(i);
+ return dtoa_result = MALLOC(i);
}
#else
-#define rv_alloc(i) xmalloc(i)
+#define rv_alloc(i) MALLOC(i)
#endif
static char *
@@ -2550,7 +2602,7 @@ nrv_alloc(const char *s, char **rve, size_t n)
static void
freedtoa(char *s)
{
- xfree(s);
+ FREE(s);
}
#endif
diff --git a/util.c b/util.c
index 6db8ddbfbe..8ec0cd60e5 100644
--- a/util.c
+++ b/util.c
@@ -29,6 +29,7 @@
#include "internal/sanitizers.h"
#include "internal/util.h"
#include "ruby/util.h"
+#include "ruby_atomic.h"
const char ruby_hexdigits[] = "0123456789abcdef0123456789ABCDEF";
#define hexdigit ruby_hexdigits
diff --git a/version.h b/version.h
index 17c6406292..1ca6c45f81 100644
--- a/version.h
+++ b/version.h
@@ -12,7 +12,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 0
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 53
+#define RUBY_PATCHLEVEL 54
#define RUBY_RELEASE_YEAR 2021
#define RUBY_RELEASE_MONTH 3