8000 Merge pull request #28435 from charris/backport-28418 · numpy/numpy@17678bf · GitHub
[go: up one dir, main page]

Skip to content

Commit 17678bf

Browse files
authored
Merge pull request #28435 from charris/backport-28418
BUG: Fix searchsorted and CheckFromAny byte-swapping logic
2 parents d6580bc + 2966a6d commit 17678bf

File tree

3 files changed

+21
-21
lines changed

3 files changed

+21
-21
lines changed

numpy/_core/src/multiarray/ctors.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,32 +1821,30 @@ PyArray_CheckFromAny(PyObject *op, PyArray_Descr *descr, int min_depth,
18211821
* Internal version of PyArray_CheckFromAny that accepts a dtypemeta. Borrows
18221822
* references to the descriptor and dtype.
18231823
*/
1824-
18251824
NPY_NO_EXPORT PyObject *
18261825
PyArray_CheckFromAny_int(PyObject *op, PyArray_Descr *in_descr,
18271826
PyArray_DTypeMeta *in_DType, int min_depth,
18281827
int max_depth, int requires, PyObject *context)
18291828
{
18301829
PyObject *obj;
1830+
Py_XINCREF(in_descr); /* take ownership as we may replace it */
18311831
if (requires & NPY_ARRAY_NOTSWAPPED) {
1832-
if (!in_descr && PyArray_Check(op) &&
1833-
PyArray_ISBYTESWAPPED((PyArrayObject* )op)) {
1834-
in_descr = PyArray_DescrNew(PyArray_DESCR((PyArrayObject *)op));
1832+
if (!in_descr && PyArray_Check(op)) {
1833+
in_descr = PyArray_DESCR((PyArrayObject *)op);
1834+
Py_INCREF(in_descr);
1835+
}
1836+
if (in_descr) {
1837+
PyArray_DESCR_REPLACE_CANONICAL(in_descr);
18351838
if (in_descr == NULL) {
18361839
return NULL;
18371840
}
18381841
}
1839-
else if (in_descr && !PyArray_ISNBO(in_descr->byteorder)) {
1840-
PyArray_DESCR_REPLACE(in_descr);
1841-
}
1842-
if (in_descr && in_descr->byteorder != NPY_IGNORE && in_descr->byteorder != NPY_NATIVE) {
1843-
in_descr->byteorder = NPY_NATIVE;
1844-
}
18451842
}
18461843

18471844
int was_scalar;
18481845
obj = PyArray_FromAny_int(op, in_descr, in_DType, min_depth,
18491846
max_depth, requires, context, &was_scalar);
1847+
Py_XDECREF(in_descr);
18501848
if (obj == NULL) {
18511849
return NULL;
18521850
}

numpy/_core/src/multiarray/item_selection.c

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2111,7 +2111,6 @@ PyArray_SearchSorted(PyArrayObject *op1, PyObject *op2,
21112111
if (dtype == NULL) {
21122112
return NULL;
21132113
}
2114-
/* refs to dtype we own = 1 */
21152114

21162115
/* Look for binary search function */
21172116
if (perm) {
@@ -2122,26 +2121,23 @@ PyArray_SearchSorted(PyArrayObject *op1, PyObject *op2,
21222121
}
21232122
if (binsearch == NULL && argbinsearch == NULL) {
21242123
PyErr_SetString(PyExc_TypeError, "compare not supported for type");
2125-
/* refs to dtype we own = 1 */
21262124
Py_DECREF(dtype);
2127-
/* refs to dtype we own = 0 */
21282125
return NULL;
21292126
}
21302127

2131-
/* need ap2 as contiguous array and of right type */
2132-
/* refs to dtype we own = 1 */
2133-
Py_INCREF(dtype);
2134-
/* refs to dtype we own = 2 */
2128+
/* need ap2 as contiguous array and of right dtype (note: steals dtype reference) */
21352129
ap2 = (PyArrayObject *)PyArray_CheckFromAny(op2, dtype,
21362130
0, 0,
21372131
NPY_ARRAY_CARRAY_RO | NPY_ARRAY_NOTSWAPPED,
21382132
NULL);
2139-
/* refs to dtype we own = 1, array creation steals one even on failure */
21402133
if (ap2 == NULL) {
2141-
Py_DECREF(dtype);
2142-
/* refs to dtype we own = 0 */
21432134
return NULL;
21442135
}
2136+
/*
2137+
* The dtype reference we had was used for creating ap2, which may have
2138+
* replaced it with another. So here we copy the dtype of ap2 and use it for `ap1`.
2139+
*/
2140+
dtype = (PyArray_Descr *)Py_NewRef(PyArray_DESCR(ap2));
21452141

21462142
/*
21472143
* If the needle (ap2) is larger than the haystack (op1) we copy the
@@ -2150,9 +2146,9 @@ PyArray_SearchSorted(PyArrayObject *op1, PyObject *op2,
21502146
if (PyArray_SIZE(ap2) > PyArray_SIZE(op1)) {
21512147
ap1_flags |= NPY_ARRAY_CARRAY_RO;
21522148
}
2149+
/* dtype is stolen, after this we have no reference */
21532150
ap1 = (PyArrayObject *)PyArray_CheckFromAny((PyObject *)op1, dtype,
21542151
1, 1, ap1_flags, NULL);
2155-
/* refs to dtype we own = 0, array creation steals one even on failure */
21562152
if (ap1 == NULL) {
21572153
goto fail;
21582154
}

numpy/_core/tests/test_regression.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2655,3 +2655,9 @@ def test_sort_overlap(self):
26552655
inp = np.linspace(0, size, num=size, dtype=np.intc)
26562656
out = np.sort(inp)
26572657
assert_equal(inp, out)
2658+
2659+
def test_searchsorted_structured(self):
2660+
# gh-28190
2661+
x = np.array([(0, 1.)], dtype=[('time', '<i8'), ('value', '<f8')])
2662+
y = np.array((0, 0.), dtype=[('time', '<i8'), ('value', '<f8')])
2663+
x.searchsorted(y)

0 commit comments

Comments
 (0)
0