diff options
author | Devin Jeanpierre <jeanpierreda@google.com> | 2016-02-22 08:00:42 -0800 |
---|---|---|
committer | Devin Jeanpierre <jeanpierreda@google.com> | 2016-02-22 08:00:42 -0800 |
commit | 9cdff27107b5feb0f6bfe5c408970716b19aa93d (patch) | |
tree | c162935e5b1157f1d45a0728f86fdde49ad27231 | |
parent | e5c1ac175722bc58e74aac4e6d9138adf9260ec6 (diff) | |
download | numpy-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.pyx | 36 |
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) |