以下代码会导致出现分段错误。我不确定为什么......
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]
完美无缺,并按预期返回列表。
有没有人对此有解释?在输入intbitset
ctr?
我已经在Python 3.6.3和2.7.13上进行了测试(需要将zip
更改为itertools.izip
)。两者都崩溃了。 intbitset
版本为2.3.0
答案 0 :(得分:0)
这里有一些有趣的事情:
...
success: function(response) {
alert('Успешно получен ответ:!'+ response.data);
document.getElementById('consumed_values').innerHTML = response.data;
draw();
},
...
观察对$ 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_Display
的来电。看起来Python试图显示错误,但在此过程中崩溃了。实际上,这不会崩溃:
PyTraceBack_Print
相反,它输出以下内容:
try:
intbitset([x for x in arr])
except Exception as ex:
print(repr(ex))
引发此异常here in intbitset.__cinit__
。请注意__cinit__
是一个特殊的Cython函数。
它是针对另一个异常而引发的,来自{nnty C代码中的gen_arrtype_subscript
。它可以通过索引这样的标量来触发:
ValueError('retrieving integers from rhs is impossible: invalid index to scalar variable.')
>>> 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.
触发此异常的原因是this line:
intbitset
事实上,numpy标量(在这种情况下为 tuple_of_tuples = rhs and hasattr(rhs, '__getitem__') and hasattr(rhs[0], '__getitem__')
)做有一个numpy.int64
,如果你调用它们就不喜欢它。这会导致__getitem__
错误地认为它正在接收sequence made of tuples,这会触发对异常引发intbitset
的调用。
这解释了为什么如果传递生成器__getitem__
它不会崩溃:它没有intbitset(x for x in arr)
,因此intbitset会输入不同的代码路径。如果您直接传递__getitem__
,则intbitset(arr)
行会在尝试将tuple_of_tuples
转换为arr
时触发另一个例外:
bool
这个异常是numpy的非Pythonic(与列表转换为ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
的方式不一致),但这就是它的工作方式。
那么为什么bool
异常导致段错误,即使invalid index to scalar
没有?事实上,如果我把truth value of an array
放在它之后,它们最终都会崩溃,所以在两种情况下显然都是未定义的行为,而且运气有时它不会崩溃。
我的猜测是raise ValueError()
通过从intbitset
引发异常来做出意想不到的事情。在Cython文档中没有明确禁止,所以我不确定如何或者是什么。