简体   繁体   English

回调后python cffi崩溃

[英]python cffi crashes after callback

I have a proprietary dll which interfaces with usb device, ctypes interface for it is working fine, but cffi one is crashing after calling a callback. 我有一个与USB设备接口的专有dll,ctypes接口可以正常工作,但是cffi在调用回调后崩溃了。 function SwitchOn(6) should return pointer to a struct if it finds a device and NULL if it doesnt, also if it does not find the device error callback gets called with errno=10. 如果函数SwitchOn(6)找到设备,则它应该返回指向结构的指针,如果找不到设备,则返回NULL,如果找不到设备,则使用errno = 10调用回调函数。

I am using python27, py33 behaves the same(need to remove 'import thread' to run) 我正在使用python27,py33的行为相同(需要删除``导入线程''才能运行)

Am I using it right? 我使用的对吗? How do I debug it? 我该如何调试?

Trying to adapt doc's example for my needs as abarnert suggested. abarnert建议的那样,尝试根据我的需要调整doc的示例。 It still crashes. 它仍然崩溃。 Am I doing it right? 我做对了吗?

>>> cffi.__version__
'0.7.2'

ctypes example outputs: ctypes示例输出:

10288
(10288, 10L, 1L)
0

cffi example outputs: cffi示例输出:

4504
(4504, 10L, 1L)

and crashes 并崩溃

cffi_crash.py cffi_crash.py

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 ctypes_no_crash.py

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 cffi_indirection.py

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)

According to the docs say : 根据文档

Windows: you can't yet specify the calling convention of callbacks… Use an indirection… Windows:您尚无法指定回调的调用约定...使用间接调用...

And your crash (happening immediately after return from your function) looks like exactly what you'd get by passing a cdecl function and having it called as a stdcall function: The caller (presumably the SwitchOn function in the C library) expects the callee (CFFI's wrapper around your error function) to clean up the stack; 而崩溃(从函数返回后立即发生)看起来就像通过传递cdecl函数并将其调用为stdcall函数所得到的结果一样:调用者(大概是C库中的SwitchOn函数)期望被调用者( CFFI封装您的error函数)以清理堆栈; the callee expects the caller to clean up the stack… so nobody cleans up the stack, so when SwitchOn tries to return, it's returning to one of your arguments or a local variable or some other garbage instead of to its caller. 被调用方希望调用方清理堆栈...因此没有人清理堆栈,因此SwitchOn尝试返回时,它返回的是您的参数之一或局部变量或其他垃圾,而不是其调用方。

Immediately above that, the docs show how to "use an indirection", by which they mean writing a C wrapper that you ffi.verify . 紧接其上的文档显示了如何“使用间接”,这意味着编写ffi.verify的C包装器。 (They're showing how to do it for passing a varargs callback, but it's the same idea.) (他们正在演示如何通过传递varargs回调,但这是相同的想法。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM