diff options
author | Sebastian Berg <sebastian@sipsolutions.net> | 2018-06-07 22:07:49 +0200 |
---|---|---|
committer | Sebastian Berg <sebastian@sipsolutions.net> | 2018-06-07 23:37:07 +0200 |
commit | 3e1a15791a58d33563e18f72aeb296946407b0e7 (patch) | |
tree | b96a3c9ceb9f13cd356b788ab678d189b5aa7d07 | |
parent | 9a4d75dce2442b81859152048c299c57e6610667 (diff) | |
download | numpy-3e1a15791a58d33563e18f72aeb296946407b0e7.tar.gz |
BUG: Remove invalid read in searchsorted if needle is empty
The tests are a bit ugly, but the cache otherwise hides the errors
away during testing.
The ternary operation did not work, because complex types do not like
assignment of 0.
Closes gh-11261
-rw-r--r-- | numpy/core/src/npysort/binsearch.c.src | 14 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 18 |
2 files changed, 28 insertions, 4 deletions
diff --git a/numpy/core/src/npysort/binsearch.c.src b/numpy/core/src/npysort/binsearch.c.src index a1a07039a..c04e197b7 100644 --- a/numpy/core/src/npysort/binsearch.c.src +++ b/numpy/core/src/npysort/binsearch.c.src @@ -43,7 +43,12 @@ binsearch_@side@_@suff@(const char *arr, const char *key, char *ret, { npy_intp min_idx = 0; npy_intp max_idx = arr_len; - @type@ last_key_val = *(const @type@ *)key; + @type@ last_key_val; + + if (key_len == 0) { + return; + } + last_key_val = *(const @type@ *)key; for (; key_len > 0; key_len--, key += key_str, ret += ret_str) { const @type@ key_val = *(const @type@ *)key; @@ -86,7 +91,12 @@ argbinsearch_@side@_@suff@(const char *arr, const char *key, { npy_intp min_idx = 0; npy_intp max_idx = arr_len; - @type@ last_key_val = *(const @type@ *)key; + @type@ last_key_val; + + if (key_len == 0) { + return 0; + } + last_key_val = *(const @type@ *)key; for (; key_len > 0; key_len--, key += key_str, ret += ret_str) { const @type@ key_val = *(const @type@ *)key; diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 3bc7e92c1..0c007db43 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -1994,6 +1994,12 @@ class TestMethods(object): assert_equal(b, out) b = a.searchsorted(a, 'r') assert_equal(b, out + 1) + # Test empty array, use a fresh array to get warnings in + # valgrind if access happens. + b = np.ndarray(shape=0, buffer=b'', dtype=dt).searchsorted(a, 'l') + assert_array_equal(b, np.zeros(len(a), dtype=np.intp)) + b = a.searchsorted(np.ndarray(shape=0, buffer=b'', dtype=dt), 'l') + assert_array_equal(b, np.zeros(0, dtype=np.intp)) def test_searchsorted_unicode(self): # Test searchsorted on unicode strings. @@ -2091,6 +2097,14 @@ class TestMethods(object): assert_equal(b, out) b = a.searchsorted(a, 'r', s) assert_equal(b, out + 1) + # Test empty array, use a fresh array to get warnings in + # valgrind if access happens. + b = np.ndarray(shape=0, buffer=b'', dtype=dt).searchsorted( + a, 'l', s[:0]) + assert_array_equal(b, np.zeros(len(a), dtype=np.intp)) + b = a.searchsorted( + np.ndarray(shape=0, buffer=b'', dtype=dt), 'l', s) + assert_array_equal(b, np.zeros(0, dtype=np.intp)) # Test non-contiguous sorter array a = np.array([3, 4, 1, 2, 0]) @@ -3345,7 +3359,7 @@ class TestBinop(object): def __div__(self, other): raise AssertionError('__div__ should not be called') - + def __pow__(self, exp): return SomeClass(num=self.num ** exp) @@ -3365,7 +3379,7 @@ class TestBinop(object): assert_equal(obj_arr ** 1, pow_for(1, obj_arr)) assert_equal(obj_arr ** -1, pow_for(-1, obj_arr)) assert_equal(obj_arr ** 2, pow_for(2, obj_arr)) - + class TestTemporaryElide(object): # elision is only triggered on relatively large arrays |