diff --git a/numpy/_core/include/numpy/_dtype_api.h b/numpy/_core/include/numpy/_dtype_api.h index b03804cd2310..a313cf5c74e1 100644 --- a/numpy/_core/include/numpy/_dtype_api.h +++ b/numpy/_core/include/numpy/_dtype_api.h @@ -444,5 +444,10 @@ typedef PyObject *(getitemfunction)(PyArray_Descr *, char *); */ #define NPY_DTYPE(descr) ((PyArray_DTypeMeta *)Py_TYPE(descr)) +static inline PyArray_DTypeMeta * +NPY_DT_NewRef(PyArray_DTypeMeta *o) { + Py_INCREF(o); + return o; +} #endif /* NUMPY_CORE_INCLUDE_NUMPY___DTYPE_API_H_ */ diff --git a/numpy/_core/src/multiarray/abstractdtypes.c b/numpy/_core/src/multiarray/abstractdtypes.c index a219d31c4bc1..13f1c142142f 100644 --- a/numpy/_core/src/multiarray/abstractdtypes.c +++ b/numpy/_core/src/multiarray/abstractdtypes.c @@ -154,7 +154,7 @@ int_common_dtype(PyArray_DTypeMeta *NPY_UNUSED(cls), PyArray_DTypeMeta *other) if (NPY_DT_is_legacy(other) && other->type_num < NPY_NTYPES) { if (other->type_num == NPY_BOOL) { /* Use the default integer for bools: */ - return &PyArray_IntpDType; + return NPY_DT_NewRef(&PyArray_IntpDType); } } else if (NPY_DT_is_legacy(other)) { @@ -174,7 +174,6 @@ int_common_dtype(PyArray_DTypeMeta *NPY_UNUSED(cls), PyArray_DTypeMeta *other) /* Try again with `int8`, an error may have been set, though */ PyArray_DTypeMeta *int8_dt = &PyArray_Int8DType; res = NPY_DT_CALL_common_dtype(other, int8_dt); - Py_DECREF(int8_dt); if (res == NULL) { PyErr_Clear(); } @@ -187,7 +186,6 @@ int_common_dtype(PyArray_DTypeMeta *NPY_UNUSED(cls), PyArray_DTypeMeta *other) /* And finally, we will try the default integer, just for sports... */ PyArray_DTypeMeta *default_int = &PyArray_IntpDType; res = NPY_DT_CALL_common_dtype(other, default_int); - Py_DECREF(default_int); if (res == NULL) { PyErr_Clear(); } @@ -204,7 +202,7 @@ float_common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other) if (NPY_DT_is_legacy(other) && other->type_num < NPY_NTYPES) { if (other->type_num == NPY_BOOL || PyTypeNum_ISINTEGER(other->type_num)) { /* Use the default integer for bools and ints: */ - return &PyArray_DoubleDType; + return NPY_DT_NewRef(&PyArray_DoubleDType); } } else if (other == &PyArray_PyIntAbstractDType) { @@ -215,7 +213,6 @@ float_common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other) /* This is a back-compat fallback to usually do the right thing... */ PyArray_DTypeMeta *half_dt = &PyArray_HalfDType; PyArray_DTypeMeta *res = NPY_DT_CALL_common_dtype(other, half_dt); - Py_DECREF(half_dt); if (res == NULL) { PyErr_Clear(); } @@ -228,7 +225,6 @@ float_common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other) /* Retry with double (the default float) */ PyArray_DTypeMeta *double_dt = &PyArray_DoubleDType; res = NPY_DT_CALL_common_dtype(other, double_dt); - Py_DECREF(double_dt); return res; } Py_INCREF(Py_NotImplemented); @@ -243,14 +239,13 @@ complex_common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other) if (other->type_num == NPY_BOOL || PyTypeNum_ISINTEGER(other->type_num)) { /* Use the default integer for bools and ints: */ - return &PyArray_CDoubleDType; + return NPY_DT_NewRef(&PyArray_CDoubleDType); } } else if (NPY_DT_is_legacy(other)) { /* This is a back-compat fallback to usually do the right thing... */ PyArray_DTypeMeta *cfloat_dt = &PyArray_CFloatDType; PyArray_DTypeMeta *res = NPY_DT_CALL_common_dtype(other, cfloat_dt); - Py_DECREF(cfloat_dt); if (res == NULL) { PyErr_Clear(); } @@ -263,7 +258,6 @@ complex_common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other) /* Retry with cdouble (the default complex) */ PyArray_DTypeMeta *cdouble_dt = &PyArray_CDoubleDType; res = NPY_DT_CALL_common_dtype(other, cdouble_dt); - Py_DECREF(cdouble_dt); return res; } diff --git a/numpy/_core/src/multiarray/convert_datatype.c b/numpy/_core/src/multiarray/convert_datatype.c index 964184db72d6..2fbaa0f64d65 100644 --- a/numpy/_core/src/multiarray/convert_datatype.c +++ b/numpy/_core/src/multiarray/convert_datatype.c @@ -3049,8 +3049,6 @@ PyArray_InitializeStringCasts(void) result = 0; finish: - Py_DECREF(string); - Py_DECREF(unicode); Py_XDECREF(other_dt); return result; } @@ -3733,7 +3731,6 @@ PyArray_InitializeVoidToVoidCast(void) }; int res = PyArray_AddCastingImplementation_FromSpec(&spec, 1); - Py_DECREF(Void); return res; } @@ -3915,7 +3912,6 @@ PyArray_InitializeObjectToObjectCast(void) }; int res = PyArray_AddCastingImplementation_FromSpec(&spec, 1); - Py_DECREF(Object); return res; } diff --git a/numpy/_core/src/multiarray/datetime.c b/numpy/_core/src/multiarray/datetime.c index a0cc1284b724..5748685d85b4 100644 --- a/numpy/_core/src/multiarray/datetime.c +++ b/numpy/_core/src/multiarray/datetime.c @@ -4281,10 +4281,6 @@ PyArray_InitializeDatetimeCasts() result = 0; fail: - Py_DECREF(datetime); - Py_DECREF(timedelta); - Py_DECREF(string); - Py_DECREF(unicode); Py_XDECREF(tmp); return result; } diff --git a/numpy/_core/src/multiarray/dtypemeta.c b/numpy/_core/src/multiarray/dtypemeta.c index 626b2bb81b00..f3a6dc266b55 100644 --- a/numpy/_core/src/multiarray/dtypemeta.c +++ b/numpy/_core/src/multiarray/dtypemeta.c @@ -919,13 +919,13 @@ default_builtin_common_dtype(PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other) return cls; } else if (cls->type_num == NPY_HALF || cls->type_num == NPY_FLOAT) { - return &PyArray_CFloatDType; + return NPY_DT_NewRef(&PyArray_CFloatDType); } else if (cls->type_num == NPY_DOUBLE) { - return &PyArray_CDoubleDType; + return NPY_DT_NewRef(&PyArray_CDoubleDType); } else if (cls->type_num == NPY_LONGDOUBLE) { - return &PyArray_CLongDoubleDType; + return NPY_DT_NewRef(&PyArray_CLongDoubleDType); } } else if (other == &PyArray_PyFloatAbstractDType) { diff --git a/numpy/_core/src/umath/_scaled_float_dtype.c b/numpy/_core/src/umath/_scaled_float_dtype.c index ba4396b88c5e..b338ba102a38 100644 --- a/numpy/_core/src/umath/_scaled_float_dtype.c +++ b/numpy/_core/src/umath/_scaled_float_dtype.c @@ -487,7 +487,6 @@ sfloat_init_casts(void) /* Technically, it is just a copy currently so this is fine: */ spec.flags = NPY_METH_NO_FLOATINGPOINT_ERRORS; PyArray_DTypeMeta *double_DType = &PyArray_DoubleDType; - Py_DECREF(double_DType); /* immortal anyway */ dtypes[0] = double_DType; slots[0].slot = NPY_METH_resolve_descriptors; @@ -519,7 +518,6 @@ sfloat_init_casts(void) spec.name = "sfloat_to_bool_cast"; dtypes[0] = &PyArray_SFloatDType; dtypes[1] = &PyArray_BoolDType; - Py_DECREF(dtypes[1]); /* immortal anyway */ if (PyArray_AddCastingImplementation_FromSpec(&spec, 0)) { return -1; @@ -762,7 +760,6 @@ sfloat_add_wrapping_loop(const char *ufunc_name, PyArray_DTypeMeta *dtypes[3]) ufunc, dtypes, wrapped_dtypes, &translate_given_descrs_to_double, &translate_loop_descrs); Py_DECREF(ufunc); - Py_DECREF(double_dt); return res; } @@ -849,7 +846,6 @@ sfloat_init_ufuncs(void) { * Add a promoter for both directions of multiply with double. */ PyArray_DTypeMeta *double_DType = &PyArray_DoubleDType; - Py_DECREF(double_DType); /* immortal anyway */ PyArray_DTypeMeta *promoter_dtypes[3] = { &PyArray_SFloatDType, double_DType, NULL}; diff --git a/numpy/_core/src/umath/dispatching.c b/numpy/_core/src/umath/dispatching.c index 6c86a05dfe69..e4d7f255fa88 100644 --- a/numpy/_core/src/umath/dispatching.c +++ b/numpy/_core/src/umath/dispatching.c @@ -1151,7 +1151,7 @@ object_only_ufunc_promoter(PyUFuncObject *ufunc, new_op_dtypes[i] = object_DType; } } - Py_DECREF(object_DType); + return 0; } @@ -1196,6 +1196,7 @@ logical_ufunc_promoter(PyUFuncObject *NPY_UNUSED(ufunc), else { /* Always override to boolean */ item = &PyArray_BoolDType; + Py_INCREF(item); if (op_dtypes[i] != NULL && op_dtypes[i]->type_num == NPY_OBJECT) { force_object = 1; } @@ -1219,7 +1220,7 @@ logical_ufunc_promoter(PyUFuncObject *NPY_UNUSED(ufunc), if (signature[i] != NULL) { continue; } - Py_SETREF(new_op_dtypes[i], &PyArray_ObjectDType); + Py_SETREF(new_op_dtypes[i], NPY_DT_NewRef(&PyArray_ObjectDType)); } return 0; } diff --git a/numpy/_core/src/umath/special_integer_comparisons.cpp b/numpy/_core/src/umath/special_integer_comparisons.cpp index f879319d2455..003617a4f17e 100644 --- a/numpy/_core/src/umath/special_integer_comparisons.cpp +++ b/numpy/_core/src/umath/special_integer_comparisons.cpp @@ -310,9 +310,9 @@ pyint_comparison_promoter(PyUFuncObject *NPY_UNUSED(ufunc), PyArray_DTypeMeta *op_dtypes[], PyArray_DTypeMeta *signature[], PyArray_DTypeMeta *new_op_dtypes[]) { - new_op_dtypes[0] = &PyArray_ObjectDType; - new_op_dtypes[1] = &PyArray_ObjectDType; - new_op_dtypes[2] = &PyArray_BoolDType; + new_op_dtypes[0] = NPY_DT_NewRef(&PyArray_ObjectDType); + new_op_dtypes[1] = NPY_DT_NewRef(&PyArray_ObjectDType); + new_op_dtypes[2] = NPY_DT_NewRef(&PyArray_BoolDType); return 0; } @@ -468,6 +468,5 @@ init_special_int_comparisons(PyObject *umath) finish: Py_XDECREF(info); - Py_DECREF(Bool); return res; } diff --git a/numpy/_core/src/umath/string_ufuncs.cpp b/numpy/_core/src/umath/string_ufuncs.cpp index 436435aa70d8..aeef151d505a 100644 --- a/numpy/_core/src/umath/string_ufuncs.cpp +++ b/numpy/_core/src/umath/string_ufuncs.cpp @@ -1100,8 +1100,8 @@ string_find_rfind_count_promoter(PyUFuncObject *NPY_UNUSED(ufunc), new_op_dtypes[0] = op_dtypes[0]; Py_INCREF(op_dtypes[1]); new_op_dtypes[1] = op_dtypes[1]; - new_op_dtypes[2] = &PyArray_Int64DType; - new_op_dtypes[3] = &PyArray_Int64DType; + new_op_dtypes[2] = NPY_DT_NewRef(&PyArray_Int64DType); + new_op_dtypes[3] = NPY_DT_NewRef(&PyArray_Int64DType); new_op_dtypes[4] = PyArray_DTypeFromTypeNum(NPY_DEFAULT_INT); return 0; } @@ -1116,9 +1116,9 @@ string_startswith_endswith_promoter(PyUFuncObject *NPY_UNUSED(ufunc), new_op_dtypes[0] = op_dtypes[0]; Py_INCREF(op_dtypes[1]); new_op_dtypes[1] = op_dtypes[1]; - new_op_dtypes[2] = &PyArray_Int64DType; - new_op_dtypes[3] = &PyArray_Int64DType; - new_op_dtypes[4] = &PyArray_BoolDType; + new_op_dtypes[2] = NPY_DT_NewRef(&PyArray_Int64DType); + new_op_dtypes[3] = NPY_DT_NewRef(&PyArray_Int64DType); + new_op_dtypes[4] = NPY_DT_NewRef(&PyArray_BoolDType); return 0; } @@ -1240,9 +1240,6 @@ init_comparison(PyObject *umath) res = 0; finish: - Py_DECREF(String); - Py_DECREF(Unicode); - Py_DECREF(Bool); return res; } @@ -1297,10 +1294,10 @@ init_ufunc(PyObject *umath, const char *name, const char *specname, int nin, int for (int i = 0; i < nin+nout; i++) { if (typenums[i] == NPY_OBJECT && enc == ENCODING::UTF32) { - dtypes[i] = &PyArray_UnicodeDType; + dtypes[i] = NPY_DT_NewRef(&PyArray_UnicodeDType); } else if (typenums[i] == NPY_OBJECT && enc == ENCODING::ASCII) { - dtypes[i] = &PyArray_BytesDType; + dtypes[i] = NPY_DT_NewRef(&PyArray_BytesDType); } else { dtypes[i] = PyArray_DTypeFromTypeNum(typenums[i]); diff --git a/numpy/_core/tests/test_regression.py b/numpy/_core/tests/test_regression.py index 14ae33bad843..5fbfc637f165 100644 --- a/numpy/_core/tests/test_regression.py +++ b/numpy/_core/tests/test_regression.py @@ -2573,3 +2573,8 @@ def test__array_namespace__(self): "is not supported." ): arr.__array_namespace__(api_version="2023.12") + + def test_isin_refcnt_bug(self): + # gh-25295 + for _ in range(1000): + np.isclose(np.int64(2), np.int64(2), atol=1e-15, rtol=1e-300)