首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >回调后python cffi崩溃

回调后python cffi崩溃
EN

Stack Overflow用户
提问于 2013-10-25 23:38:34
回答 1查看 2.5K关注 0票数 0

我有一个专用的dll,它与usb设备接口,ctypes接口为它工作良好,但cffi在调用回调后崩溃。函数SwitchOn(6)应该返回指向结构的指针,如果它找到了一个设备,如果它没有找到,也应该返回指向结构的指针,如果它没有找到用errno=10调用的设备错误回调。

我使用的是python27,py33的行为相同(需要删除“导入线程”才能运行)

我用得对吗?如何调试它?

正如abarnert所建议的那样,试图根据我的需要调整doc的示例。它还是会崩溃。我做得对吗?

代码语言:javascript
复制
>>> cffi.__version__
'0.7.2'

ctypes示例输出:

代码语言:javascript
复制
10288
(10288, 10L, 1L)
0

cffi示例输出:

代码语言:javascript
复制
4504
(4504, 10L, 1L)

和撞车

cffi_crash.py

代码语言:javascript
复制
import thread
def error(errno, critical):
    print(thread.get_ident(), errno, critical)

from cffi import FFI
ffi = FFI()
ffi.cdef('''
void* SwitchOn(int FPort);
typedef void(*type_func_user_error)(unsigned int, unsigned int);
void SetErrorFunction(type_func_user_error);
''')
eeg_dll = ffi.dlopen("EEG4DLL.dll")
err_cb = ffi.callback('type_func_user_error', error)

eeg_dll.SetErrorFunction(err_cb)
print(thread.get_ident())
x = eeg_dll.SwitchOn(6)
print(x)

ctypes_no_crash.py

代码语言:javascript
复制
import thread

def error(errno, critical):
    print(thread.get_ident(), errno, critical)

import ctypes
from ctypes import c_uint, WINFUNCTYPE

eeg_dll = ctypes.windll.EEG4DLL
func_user_error = WINFUNCTYPE(None, c_uint, c_uint)

SetErrorFunction = eeg_dll.SetErrorFunction
SetErrorFunction.argtypes = [func_user_error]
SetErrorFunction.restype = None

err_cb = func_user_error(error)

eeg_dll.SetErrorFunction(err_cb)
print(thread.get_ident())
x = eeg_dll.SwitchOn(6)
print(x)

cffi_indirection.py

代码语言:javascript
复制
def error(errno, critical):
    print(errno, critical)

from cffi import FFI
ffi2 = FFI()
ffi2.cdef('''
void (*python_callback)(unsigned int, unsigned int);
void *const c_callback;
''')
wr = ffi2.verify('''
    static void(*python_callback)(unsigned int x, unsigned int y);
    static void c_callback(unsigned int x, unsigned int y) {
        python_callback(x, y);
    }
''')
err_cb = ffi2.callback('void(unsigned int, unsigned int)', error)
wr.python_callback = err_cb

ffi = FFI()
ffi.cdef('''
void* SwitchOn(int FPort);
typedef void(*type_func_user_error)(unsigned int, unsigned int);
void SetErrorFunction(type_func_user_error);
''')
eeg_dll = ffi.dlopen("EEG4DLL.dll")
eeg_dll.SetErrorFunction(wr.c_callback)
x = eeg_dll.SwitchOn(6)
print(x)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-26 00:21:16

根据docs

Windows:您还不能指定回调…的调用约定使用间接…

您的崩溃(在从函数返回后立即发生)看起来与您通过传递cdecl函数并将其作为stdcall函数调用而得到的结果完全一样:调用方(想必是C库中的SwitchOn函数)希望被调用者(CFFI围绕您的error函数的包装器)清理堆栈;被调用者希望调用者清理堆栈…函数因此,没有人清理堆栈,所以当SwitchOn试图返回时,它将返回到您的一个参数或局部变量或其他垃圾,而不是返回给调用方。

在此之前,文档显示了如何“使用间接”,这意味着编写一个ffi.verify的C包装器。(他们正在展示如何传递varargs回调,但这是相同的想法。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19601016

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档