intbitset\uuuu init\uuuu导致SIGSEGV

2024-09-27 23:17:48 发布

您现在位置:Python中文网/ 问答频道 /正文

以下代码导致引发分段错误。我不知道为什么。。。你知道吗

import numpy as np
from intbitset import intbitset

arr = np.array([1,2,3,4,5])

# This works
intbitset(arr.tolist())
=> intbitset([1, 2, 3, 4, 5])

# This throws SIGSEGV
intbitset([x for x in arr])

[x for x in arr]工作正常,并按预期返回列表。你知道吗

有人对此有什么解释吗?在输入intbitsetctr之前,列表理解不是被计算成一个列表吗?你知道吗

我已经在python3.6.3和2.7.13上进行了测试(需要将zip更改为itertools.izip)。两个都撞车了。intbitset版本是2.3.0


Tags: 代码infromimportnumpy列表foras
1条回答
网友
1楼 · 发布于 2024-09-27 23:17:48

有件有趣的事:

$ gdb python 
...
(gdb) run crash.py
...
Thread 1 "python" received signal SIGSEGV, Segmentation fault.
0x00007ffff745338b in ?? () from /usr/lib/libpython3.6m.so.1.0
(gdb) bt
#0  0x00007ffff745338b in ?? ()
   from /usr/lib/libpython3.6m.so.1.0
#1  0x00007ffff74a245f in ?? ()
   from /usr/lib/libpython3.6m.so.1.0
#2  0x00007ffff73f0565 in PyList_Append ()
   from /usr/lib/libpython3.6m.so.1.0
#3  0x00007ffff73a2580 in ?? ()
   from /usr/lib/libpython3.6m.so.1.0
#4  0x00007ffff7404b55 in _PyCFunction_FastCallDict ()
   from /usr/lib/libpython3.6m.so.1.0
#5  0x00007ffff740e10f in _PyObject_FastCallDict ()
   from /usr/lib/libpython3.6m.so.1.0
#6  0x00007ffff73fc9d0 in PyFile_WriteObject ()
   from /usr/lib/libpython3.6m.so.1.0
#7  0x00007ffff74a3d6a in PyFile_WriteString ()
   from /usr/lib/libpython3.6m.so.1.0
#8  0x00007ffff74b2f9d in PyTraceBack_Print ()
   from /usr/lib/libpython3.6m.so.1.0
#9  0x00007ffff7491154 in ?? ()
   from /usr/lib/libpython3.6m.so.1.0
#10 0x00007ffff7327d14 in ?? ()
   from /usr/lib/libpython3.6m.so.1.0
#11 0x00007ffff749136e in PyErr_Display ()
   from /usr/lib/libpython3.6m.so.1.0
#12 0x00007ffff74c890a in ?? ()
   from /usr/lib/libpython3.6m.so.1.0
#13 0x00007ffff7404ad0 in _PyCFunction_FastCallDict ()
   from /usr/lib/libpython3.6m.so.1.0
#14 0x00007ffff740e10f in _PyObject_FastCallDict ()
   from /usr/lib/libpython3.6m.so.1.0
#15 0x00007ffff7492c5b in PyErr_PrintEx ()
  3.6m.so.1.0
#16 0x00007ffff74939d1 in PyRun_SimpleFileExFlags ()
   from /usr/lib/libpython3.6m.so.1.0
#17 0x00007ffff748970b in Py_Main ()
   from /usr/lib/libpython3.6m.so.1.0
#18 0x0000555555554c39 in main ()

观察对PyErr_DisplayPyTraceBack_Print的调用。看起来Python试图显示一个错误,但在这个过程中崩溃了。事实上,这不会崩溃:

try:
    intbitset([x for x in arr])
except Exception as ex:
    print(repr(ex))

相反,它输出以下内容:

ValueError('retrieving integers from rhs is impossible: invalid index to scalar variable.')

此异常是here in ^{}引发的。注意^{}是一个特殊的Cython函数。你知道吗

它是响应另一个异常而引发的,来自numpyc代码中的^{}。它可以通过索引标量触发,如下所示:

>>> import numpy as np
>>> arr = np.array([1,2,3,4,5])
>>> arr[0][0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: invalid index to scalar variable.

intbitset触发此异常的原因是this line

  tuple_of_tuples = rhs and hasattr(rhs, '__getitem__') and hasattr(rhs[0], '__getitem__')

事实上,numpy标量(numpy.int64在本例中)确实有一个__getitem__,它们只是不喜欢你调用它。这会导致intbitset错误地假设它正在接收一个sequence made of tuples,从而触发对引发__getitem__的异常的调用。你知道吗

这就解释了为什么传递一个生成器intbitset(x for x in arr)时它不会崩溃:它没有__getitem__,所以intbitset会进入一个不同的代码路径。如果直接传递intbitset(arr)tuple_of_tuples行在尝试将arr转换为bool时会触发另一个异常:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

这个异常与numpy相当不搭调(与列表转换为bool的方式不一致),但这就是它的工作方式。你知道吗

那么为什么invalid index to scalar异常会导致segfault,即使truth value of an array不会?事实上,如果我在它后面加上raise ValueError(),两个都会崩溃,所以在这两种情况下显然都是未定义的行为,而且纯粹是运气,它有时不会崩溃。你知道吗

我的猜测是intbitset通过从__cinit__引发异常,做了一些意想不到的事情。在Cython文档中没有明确禁止,所以我不知道怎么做或者做什么。你知道吗

相关问题 更多 >

    热门问题