0

问题描述

我有这个功能:

def test(unsigned int N):
    cdef int *my_arr = <int *> malloc(N * sizeof(int))
    cdef int[:] new_arr = <int[:N]>my_arr
    free(my_arr)

当我将它放在一个名为 test.pyx 的单独文件上时,编译它并从 CPython 的解释器中调用它,它工作正常。我这样称呼它:

import test
test.test(10)

当我将此函数添加到现有库(在具有多个文件和依赖项的大项目中)时,问题就来了,它编译得很好,但是当我调用它时会抛出一个错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "av/video/frame.pyx", line 37, in av.video.frame.test
    cdef int[:] new_arr = <int[:N]>my_arr
ValueError

如您所见,它特别抱怨这一行:

cdef int[:] new_arr = <int[:N]>my_arr

两种情况下的函数完全一样,而且我传递了相同的N值,真的很奇怪。

有谁知道在哪种情况下可以简单地强制int *转换来int[:]抛出 ValueError?


语境

我正在尝试向 PyAV 库添加一些功能,因此我将该功能添加到此文件中:

https://github.com/PyAV-Org/PyAV/blob/main/av/video/frame.pyx

当我这样称呼它时它会抛出:

import av
av.video.frame.test(10)

我在 MacOS 10.15.7 上,使用 Python 3.7.7 和 Cython 0.29.21 和 Clang 11.0.3 编译器。


更新 1

我已经检查了 Cython 为该test()函数生成的 C 代码,两种情况下都是相同的,这是为有问题的行生成的代码:

 /* "av/video/frame.pyx":37
 * def test(unsigned int N):
 *     cdef int *my_arr = <int *> malloc(N * sizeof(int))
 *     cdef int[:] new_arr = <int[:N]>my_arr             # <<<<<<<<<<<<<<
 *     free(my_arr)
 * 
 */
  if (!__pyx_v_my_arr) {
    PyErr_SetString(PyExc_ValueError,"Cannot create cython.array from NULL pointer");
    __PYX_ERR(0, 37, __pyx_L1_error)
  }
  __pyx_t_3 = __pyx_format_from_typeinfo(&__Pyx_TypeInfo_int); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 37, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_2 = Py_BuildValue((char*) "("  __PYX_BUILD_PY_SSIZE_T  ")", ((Py_ssize_t)__pyx_v_N)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 37, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_1 = __pyx_array_new(__pyx_t_2, sizeof(int), PyBytes_AS_STRING(__pyx_t_3), (char *) "c", (char *) __pyx_v_my_arr);
  if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 37, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_4 = __Pyx_PyObject_to_MemoryviewSlice_ds_int(((PyObject *)__pyx_t_1), PyBUF_WRITABLE); if (unlikely(!__pyx_t_4.memview)) __PYX_ERR(0, 37, __pyx_L1_error)
  __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0;
  __pyx_v_new_arr = __pyx_t_4;
  __pyx_t_4.memview = NULL;
  __pyx_t_4.data = NULL;

所以我开始用调用注释行,__PYX_ERR()发现引发 ValueError 的行是这样的:

__pyx_t_4 = __Pyx_PyObject_to_MemoryviewSlice_ds_int(((PyObject *)__pyx_t_1), PyBUF_WRITABLE); if (unlikely(!__pyx_t_4.memview)) __PYX_ERR(0, 37, __pyx_L1_error)

这一行更新了__Pyx_memviewslice之前声明的 a:

__Pyx_memviewslice __pyx_t_4 = { 0, 0, { 0 }, { 0 }, { 0 } };

这个函数很可能会设置错误:

__Pyx_PyObject_to_MemoryviewSlice_ds_int()

所以也许演员(PyObject *)__pyx_t_1做错了什么或者__pyx_t_1不是它所期望的。

但我真的不知道这一切是如何工作的,所以也许还有其他原因导致这种行为,比如一些编译器标志?

4

0 回答 0