python - 使用 Python Ctypes 和 C++ 时如何解决段错误?

标签 python c++ ctypes

假设我在 C++ 中有以下两个函数签名:

BYTE* init( BYTE* Options, BYTE* Buffer )

和:

int next( BYTE* interface, BYTE* Buffer )

我的想法是,我首先在 C++ 中初始化一个 Interface 类,然后从 Python 调用 next 函数,并引用该类。

第一个函数通过以下方式返回指向接口(interface)的 BYTE 指针:

Interface*  interface;
// initialize stuff
return((BYTE*) interface);

我在 Python 中这样调用它:

class Foo:
  def init(self, data):
    # left out: setting options_ptr
    buf = (c_ubyte * len(data.bytes)).from_buffer_copy(data.bytes)
    init_fun = getattr(self.dll, '?init@@YAPAEPAE0HH@Z')
    init_fun.restype = POINTER(c_ubyte)
    self.interface_ptr = init_fun(options_ptr, buf)
    # this works fine!

  def next(self, data):
    # create buf from other data
    buf = (c_ubyte * len(data.bytes)).from_buffer_copy(data.bytes)
    next_fun = getattr(self.dll, '?next@@YAHPAE0HN@Z')
    ret = next_fun(self.interface_ptr, buf)
    # I randomly get segmentation faults here

我从外部调用它,例如:

foo = Foo()
foo.init(some_data)
foo.next(some_other_data)
# ...
foo.next(some_additional_data)

现在,当我运行它时,出现段错误:

[1]    24712 segmentation fault  python -u test.py

有时它发生在第一次调用 .next() 之后,有时它发生在第十一次调用 .next() 之后——完全随机。

API 有一个 C++ 测试代码,其工作方式如下:

BYTE Buffer[500000];
UTIN BufSize=0;
BYTE* Interface;

# not shown here: fill buffer with something
Interface = init(Buffer);
while(true) {
    # not shown here: fill buffer with other data
    int ret = next(Interface, Buffer);
}

现在,由于我无法显示确切的代码,因为它更大且专有,问题是:我如何解决此类段错误?我可以在抛出异常时中断(当使用 VS2012 调试),但它在这里中断:

显然,这没有用,因为在指示的行上实际上没有对任何缓冲区执行任何操作。变量值也很神秘:

在我的例子中,data 是一个 BitString目的。如果 C++ 代码对传递的缓冲区进行内存操作,会不会是问题所在?或者某些数据在仍然需要时被 Python 垃圾收集?

更一般地说,如何确保在使用 Ctypes 时不会出现段错误?我知道底层 DLL API 工作正常并且不会崩溃。


更新:当我将 buf 设为实例变量时,例如self._buf,我得到一个段错误,但它在调试期间在不同的位置中断:

最佳答案

我有一些误解,所有这些都导致了问题:

  • 当您在 Python 中创建一个 Ctypes 对象并将其传递给一个 C 函数,并且不再需要该 Python 对象时,它(可能)被垃圾收集并且不再位于 C 期望它的内存堆栈中成为。

    因此,使缓冲区成为一个实例变量,例如self._buf.

  • C 函数期望数据是可变的。如果 C 函数实际上并不将数据复制到其他地方而是直接在缓冲区上工作,则它需要是可变的。 Ctypes 文档指定了这一点:

    Assigning a new value to instances of the pointer types c_char_p, c_wchar_p, and c_void_p changes the memory location they point to, not the contents of the memory block (of course not, because Python strings are immutable).

    You should be careful, however, not to pass them to functions expecting pointers to mutable memory. If you need mutable memory blocks, ctypes has a create_string_buffer() function which creates these in various ways. The current memory block contents can be accessed (or changed) with the raw property; if you want to access it as NUL terminated string, use the value property:

    所以,我做了这样的事情:

    self._buf = create_string_buffer(500000)
    self._buf.value = startdata.bytes
  • 缓冲区应该像示例代码中所示的普通数组一样在 Python 中使用,在其中填充缓冲区并处理其中的数据。因此,对于我的 .next() 方法,我这样做了:
    self._buf.value = nextdata.bytes

现在我的程序按预期运行了。

关于python - 使用 Python Ctypes 和 C++ 时如何解决段错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29628046/

相关文章:

c++ - 将私有(private)对象变量与用户输入的变量进行比较

python - 使用 numpy/ctypes 公开 C 分配的内存缓冲区的更安全方法?

python - Python中所有向量组合的集合

python:在一个字符后拆分字符串

python - 将 WindowsPath 转换为字符串

python - 是否可以让 Python 自动检测动态库中的函数?

python - 从 Python 访问 C 声明的嵌套结构

python 到 arduino 串口读写

c++ - JPG 图像在 cvCreateImageHeader 之后从 30KB 变为 300KB

c++ - 如何覆盖 Queue STL 对象中的某些函数?