intbitset __init__导致SIGSEGV

时间:2018-02-28 12:28:58

标签: 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]完美无缺,并按预期返回列表。

有没有人对此有解释?在输入intbitset ctr?

之前,列表推导不会被评估到列表中吗?

我已经在Python 3.6.3和2.7.13上进行了测试(需要将zip更改为itertools.izip)。两者都崩溃了。 intbitset版本为2.3.0

1 个答案:

答案 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文档中没有明确禁止,所以我不确定如何或者是什么。