调试Python ctypes段错误

11

我正在尝试将一些使用Python ctypes的代码从一个特定于Windows的程序迁移到与我的库的Linux端口链接。下面是描述我的问题的最短Python代码示例。当我尝试执行它时,Python中的examine_arguments()会导致段错误。我在崩溃函数调用处放置了一个printf语句,但从未执行,这让我认为问题出在ctypes代码中。

import ctypes

avidll = ctypes.CDLL("libavxsynth.so")


class AVS_Value(ctypes.Structure, object):
    def __init__(self, val=None):
        self.type=ctypes.c_short(105) # 'i'
        self.array_size = 5
        self.d.i = 99


class U(ctypes.Union):
    _fields_ = [("c", ctypes.c_void_p),
                ("b", ctypes.c_long),
                ("i", ctypes.c_int),
                ("f", ctypes.c_float),
                ("s", ctypes.c_char_p),
                ("a", ctypes.POINTER(AVS_Value))]


AVS_Value._fields_ = [("type", ctypes.c_short),
                      ("array_size", ctypes.c_short),
                      ("d", U)]


avs_create_script_environment = avidll.avs_create_script_environment
avs_create_script_environment.restype = ctypes.c_void_p
avs_create_script_environment.argtypes = [ctypes.c_int]

avs_set_var = avidll.avs_set_var
avs_set_var.restype = ctypes.c_int
avs_set_var.argtypes = [ctypes.c_void_p, ctypes.c_char_p, AVS_Value]


env = avs_create_script_environment(2)
val = AVS_Value()
res = avs_set_var(env, b'test', val)

我的库在头文件中有以下内容,一个简单的C程序执行上述操作(调用create_script_environment后跟set_var)是正常的。查看我的库放在控制台上的日志信息,崩溃发生在我尝试输入avs_set_var时。

typedef struct AVS_ScriptEnvironment AVS_ScriptEnvironment;
typedef struct AVS_Value AVS_Value;
struct AVS_Value {
  short type;  // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, or 'l'ong
               // for some function e'rror
  short array_size;
  union {
    void * clip; // do not use directly, use avs_take_clip
    char boolean;
    int integer;
    float floating_pt;
    const char * string;
    const AVS_Value * array;
  } d;
};
AVS_ScriptEnvironment * avs_create_script_environment(int version);
int avs_set_var(AVS_ScriptEnvironment *, const char* name, AVS_Value val);

我尝试从GDB回溯调用,但我不理解如何解释结果,也不太了解如何使用GDB。

#0  0x00007ffff61d6490 in examine_argument () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#1  0x00007ffff61d65ba in ffi_prep_cif_machdep () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#2  0x00007ffff61d3447 in ffi_prep_cif () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#3  0x00007ffff61c7275 in _ctypes_callproc () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#4  0x00007ffff61c7aa2 in PyCFuncPtr_call.2798 () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#5  0x00000000004c7c76 in PyObject_Call ()
#6  0x000000000042aa4a in PyEval_EvalFrameEx ()
#7  0x00000000004317f2 in PyEval_EvalCodeEx ()
#8  0x000000000054b171 in PyRun_FileExFlags ()
#9  0x000000000054b7d8 in PyRun_SimpleFileExFlags ()
#10 0x000000000054c5d6 in Py_Main ()
#11 0x00007ffff68e576d in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
#12 0x000000000041b931 in _start ()

我不知道如何解决这个问题。我已经查看了调用类型的详细信息,但并没有发现明显错误。我是否犯了某些特定于平台的类型用法错误?

编辑 ctypes模块中存在32位与64位架构之间的问题。当我使用32位版本的库和32位Python进行测试时,它成功运行。在64位上,它在同一位置引起“段错误”。


我复制了这段代码,重新排列了明显贴错的部分,并对两个函数进行了虚拟实现。我将其编译为x86_64,在64位Python 2.7(Ubuntu Natty,gcc 4.5.2,Python 2.7.1,eglibc 2.13)下运行,一切正常。在这里就把问题归咎于ctypes似乎为时过早了;也许你可以提供一个更完整的打破例子? - the paul
我清理了代码示例。似乎segfault与union是AVS_Value类的一部分有关。当我将其替换为类似ctypes.c_int或ctypes.c_void_p的东西时,程序不再segfault。我开始认为问题出在Ubuntu上安装的Python上 - 我正在使用Ubuntu 12.04,GCC 4.6.3,Python 2.7。 - user1505563
你的boolean变量是类型为char,但在Python中,你已将b声明为c_long - Mark Tolonen
代码看起来除此之外都正确,并且使用我的虚拟实现也能正常工作,因此问题可能出在 C 代码上。 - Mark Tolonen
1个回答

0

尝试使用c_void_p来表示不透明的AVS_ScriptEnvironment*

avs_create_script_environment.restype = c_void_p

并且:

avs_set_var.argtypes=[c_void_p,ctypes.c_char_p,AVS_Value]

明确将返回类型设置为c_void_p也没有帮助。我也不明白为什么会有帮助,因为Python在进入下一个函数之前就崩溃了,所以该指针没有被使用。 - user1505563
在64位代码中,这会有所不同,因为指针将被截断为c_int(32位)。 - Mark Tolonen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接