summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2018-06-07 22:07:49 +0200
committerSebastian Berg <sebastian@sipsolutions.net>2018-06-07 23:37:07 +0200
commit3e1a15791a58d33563e18f72aeb296946407b0e7 (patch)
treeb96a3c9ceb9f13cd356b788ab678d189b5aa7d07
parent9a4d75dce2442b81859152048c299c57e6610667 (diff)
downloadnumpy-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.src14
-rw-r--r--numpy/core/tests/test_multiarray.py18
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