gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:52:44 25 4
gpt4 key购买 nike

假设我在 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com