Open rgommers opened 9 months ago
I can reproduce that warning (although testing it on scipy's code is the first time I've seen it).
I think it's a false positive. The internal code in question:
static CYTHON_INLINE void __Pyx_XCLEAR_MEMVIEW(__Pyx_memviewslice *memslice,
int have_gil, int lineno) {
__pyx_nonatomic_int_type old_acquisition_count;
struct __pyx_memoryview_obj *memview = memslice->memview;
if (unlikely(!memview || (PyObject *) memview == Py_None)) {
memslice->memview = NULL;
return;
}
old_acquisition_count = __pyx_sub_acquisition_count(memview);
So I think it's detected that memslice->memview
points to a _Py_NoneStruct
object, and hasn't realized that None
is a singleton so the memview == Py_None
prevents __pyx_sub_acquisition_count
from ever being run in that case.
In Cython <3 the reference counting was slightly more indirect the compiler probably couldn't work as much out.
If I comment out y = None
at the end of the loop then the warning goes away.
It'd definitely be good if Cython could avoid generating this warning. We could possibly do so just by not inlining __Pyx_XCLEAR_MEMVIEW
but that might have its own performance costs (or gains...). I can't think of too many other things we could do.
If we accept my belief that it's a false positive, then I think Scipy can safely ignore it for now. I just haven't quite convinced myself I'm completely sure I'm right yet.
We could possibly do so just by not inlining
__Pyx_XCLEAR_MEMVIEW
but that might have its own performance costs (or gains...). I can't think of too many other things we could do.
Confirmed that this does make the warning go away. Still not sure if we want to do it though.
Thanks for having a look @da-woods.
If I comment out
y = None
at the end of the loop then the warning goes away.
That y = None
line doesn't seem to do much, it was probably just added as a safety measure. But looks like it can be deleted. So no warnings from Cython is always good, but the decision here shouldn't matter to SciPy.
Hmm, not 100% of that "can be deleted". The code generated for it is:
__pyx_t_8 = __Pyx_PyObject_to_MemoryviewSlice_dc_double(Py_None, PyBUF_WRITABLE); if (unlikely(!__pyx_t_8.memview)) __PYX_ERR(0, 184, __pyx_L1_error)
__PYX_XCLEAR_MEMVIEW(&__pyx_v_y, 1);
__pyx_v_y = __pyx_t_8;
__pyx_t_8.memview = NULL;
__pyx_t_8.data = NULL;
}
Which may be needed for bookkeeping. However, for the y = xs[ip]
line higher up in the for-loop we see the same pattern:
* y = xs[ip] # <<<<<<<<<<<<<<
if (unlikely(__pyx_v_xs == Py_None)) {
PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable");
__PYX_ERR(0, 174, __pyx_L1_error)
}
__pyx_t_8 = __Pyx_PyObject_to_MemoryviewSlice_dc_double(PyTuple_GET_ITEM(__pyx_v_xs, __pyx_v_ip), PyBUF_WRITABLE); if (unlikely(!__pyx_t_8.memview)) __PYX_ERR(0, 174, __pyx_L1_error)
__PYX_XCLEAR_MEMVIEW(&__pyx_v_y, 1);
__pyx_v_y = __pyx_t_8;
__pyx_t_8.memview = NULL;
__pyx_t_8.data = NULL;
It's not clear to me if this line makes any difference or Cython gives any kind of guarantee for this code:
# grab array pointers
nxx[ip] = y.shape[0]
xx[ip] = <double*>&y[0]
y = None
I don't think it makes any difference - the assignment further up the loop takes care of the reference counting either way. Unless you're doing if y is None
or possibly if y
then I think it should all be largely the same.
I don't see why it should make any difference to the "grab array pointers" code either.
Describe the bug
This warning is new in Cython 3 I believe:
Code to reproduce the behaviour:
I'm seeing this when building SciPy with Python 3.10 and GCC 12.2.0. The warning is triggered here: https://github.com/scipy/scipy/blob/2d6be1c71322c33a7151f1620d633711715b6a7b/scipy/interpolate/_ppoly.pyx#L174
That code seems to come down to:
And then calling that with an
xs
input which is a tuple of ndarrays.Perhaps it's clear to someone what is happening here without having to create a full standalone reproducer.
Expected behaviour
No build warning.
OS
Linux
Python version
3.10.10
Cython version
3.0.7 (also present in 3.0.4)
Additional context
No response