summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDevin Jeanpierre <jeanpierreda@google.com>2016-02-22 08:00:42 -0800
committerDevin Jeanpierre <jeanpierreda@google.com>2016-02-22 08:00:42 -0800
commit9cdff27107b5feb0f6bfe5c408970716b19aa93d (patch)
treec162935e5b1157f1d45a0728f86fdde49ad27231
parente5c1ac175722bc58e74aac4e6d9138adf9260ec6 (diff)
downloadnumpy-9cdff27107b5feb0f6bfe5c408970716b19aa93d.tar.gz
BUG: Remove data race in mtrand: two threads could mutate the state.
E.g.: np.random.random_sample() uses the GIL for synchronization np.random.random_sample(1) releases the GIL and uses a separate lock. This means that both can run simultaneously, causing a data race when mutating the random number generator's state, which could lead to buffer overflow (from incrementing state->pos). The fix here is to always use the separate lock, so that exactly one thread at a time is mutating the random number generator's state.
-rw-r--r--numpy/random/mtrand/mtrand.pyx36
1 files changed, 27 insertions, 9 deletions
diff --git a/numpy/random/mtrand/mtrand.pyx b/numpy/random/mtrand/mtrand.pyx
index b05d86747..964129a8c 100644
--- a/numpy/random/mtrand/mtrand.pyx
+++ b/numpy/random/mtrand/mtrand.pyx
@@ -158,7 +158,9 @@ cdef object cont0_array(rk_state *state, rk_cont0 func, object size,
cdef npy_intp i
if size is None:
- return func(state)
+ with lock, nogil:
+ rv = func(state)
+ return rv
else:
array = <ndarray>np.empty(size, np.float64)
length = PyArray_SIZE(array)
@@ -177,7 +179,9 @@ cdef object cont1_array_sc(rk_state *state, rk_cont1 func, object size, double a
cdef npy_intp i
if size is None:
- return func(state, a)
+ with lock, nogil:
+ rv = func(state, a)
+ return rv
else:
array = <ndarray>np.empty(size, np.float64)
length = PyArray_SIZE(array)
@@ -229,7 +233,9 @@ cdef object cont2_array_sc(rk_state *state, rk_cont2 func, object size, double a
cdef npy_intp i
if size is None:
- return func(state, a, b)
+ with lock, nogil:
+ rv = func(state, a, b)
+ return rv
else:
array = <ndarray>np.empty(size, np.float64)
length = PyArray_SIZE(array)
@@ -278,7 +284,9 @@ cdef object cont3_array_sc(rk_state *state, rk_cont3 func, object size, double a
cdef npy_intp i
if size is None:
- return func(state, a, b, c)
+ with lock, nogil:
+ rv = func(state, a, b, c)
+ return rv
else:
array = <ndarray>np.empty(size, np.float64)
length = PyArray_SIZE(array)
@@ -327,7 +335,9 @@ cdef object disc0_array(rk_state *state, rk_disc0 func, object size, object lock
cdef npy_intp i
if size is None:
- return func(state)
+ with lock, nogil:
+ rv = func(state)
+ return rv
else:
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)
@@ -345,7 +355,9 @@ cdef object discnp_array_sc(rk_state *state, rk_discnp func, object size,
cdef npy_intp i
if size is None:
- return func(state, n, p)
+ with lock, nogil:
+ rv = func(state, n, p)
+ return rv
else:
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)
@@ -392,7 +404,9 @@ cdef object discdd_array_sc(rk_state *state, rk_discdd func, object size,
cdef npy_intp i
if size is None:
- return func(state, n, p)
+ with lock, nogil:
+ rv = func(state, n, p)
+ return rv
else:
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)
@@ -439,7 +453,9 @@ cdef object discnmN_array_sc(rk_state *state, rk_discnmN func, object size,
cdef npy_intp i
if size is None:
- return func(state, n, m, N)
+ with lock, nogil:
+ rv = func(state, n, m, N)
+ return rv
else:
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)
@@ -488,7 +504,9 @@ cdef object discd_array_sc(rk_state *state, rk_discd func, object size,
cdef npy_intp i
if size is None:
- return func(state, a)
+ with lock, nogil:
+ rv = func(state, a)
+ return rv
else:
array = <ndarray>np.empty(size, int)
length = PyArray_SIZE(array)