Python C API-使用比较函数导致';分段错误';

Python C API-使用比较函数导致';分段错误';,python,c,api,Python,C,Api,我目前正在学习用C编写Python扩展,一切似乎都进行得很顺利。然而,当我尝试使用比较函数时,它们都会导致分段错误。例如: #include "Python.h" int test(void) { int result; printf("Before compare...\n"); result = PyObject_Compare(PyInt_FromLong(1), PyInt_FromLong(3)); printf("result= %d\n", res

我目前正在学习用C编写Python扩展,一切似乎都进行得很顺利。然而,当我尝试使用比较函数时,它们都会导致分段错误。例如:

#include "Python.h"

int test(void) {
    int result;
    printf("Before compare...\n");
    result = PyObject_Compare(PyInt_FromLong(1), PyInt_FromLong(3));
    printf("result= %d\n", result);
    return 0;   
}
从Python执行
test()
(我使用了ctypes)会得到以下输出:

Before compare...
Segmentation fault
对于其他比较函数,如:
PyObject\u cmp
…等,我也遇到了这种情况

谢谢你的帮助

更多信息: 我首先将文件(test.c)编译到一个共享库中:

$> python-config --cflags
-I/usr/include/python2.7 -I/usr/include/python2.7 -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes
$> python-config --ldflags
-L/usr/lib/python2.7/config -lpthread -ldl -lutil -lm -lpython2.7 -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions

$> gcc -c $(python-config --cflags) ./test.c -o test.o
$> gcc -shared  ./test.o  $(python-config --ldflags) -o libtest.so
然后,我从Python启动函数,如下所示:

import ctypes
testlib = ctypes.CDLL('./libtest.so')

testlib.test()
编辑: 使用Viktor给出的测试

$> gcc -o dlltest test.c -ldl
$> gdb dlltest
(gdb) run
Starting program: dlltest 
[Thread debugging using libthread_db enabled]
Cannot find new threads: generic error
(gdb) 
所以我这样做了:

$> LD_PRELOAD=libpthread-2.13.so gdb dlltest
(gdb) run
Starting program: dlltest
[Thread debugging using libthread_db enabled]
Before compare...
result= -1
[Inferior 1 (process 3274) exited normally]
(gdb)
编辑2:
“test()”函数中没有Python解释器的初始化(没有Py_初始化调用)

PyInt_FromLong()返回指向内部数组的指针,该数组在您的示例中未初始化。因此,您得到一些无效指针并将其传递给Py_Compare()函数会使解释器崩溃

有关初始化的详细信息,请参见此处:

至少尝试在test()函数的开头添加“Py_Initialize()”调用

编辑:

有趣的是,如果使用以下程序从C运行libtest.test,那么来自GDB的堆栈跟踪是什么:

#include <dlfcn.h>

typedef int (*fcn)();

int main()
{
    void* dll = dlopen("libtest.so", RTLD_LAZY);

    /* dlerror checks here */

    fcn Test = (fcn)dlsym(dll, "test");

    Test();

    dclose(dll);

    return 0;
}
#包括
typedef int(*fcn)();
int main()
{
void*dll=dlopen(“libtest.so”,RTLD_-LAZY);
/*这里有错误检查*/
fcn测试=(fcn)dlsym(dll,“测试”);
Test();
dclose(dll);
返回0;
}
编辑2:

  • 编译测试(gcc-odlltest.c-ldl)

  • 运行“gdb dlltest”

  • 在gdb提示符中键入命令“run”

  • 看看它是否崩溃

  • 如果是,请在gdb的提示符中键入回溯

  • 编辑3:

    不清楚坠机地点。尝试在每次printf()调用后添加“fflush(stdout);”以确保错误已被打印出来


    如果“result=-1”出现在基于python的应用程序中,则错误出现在ctypes中,而不是libtest中。因此,

    在“test()”函数中没有python解释器的初始化(没有Py\u初始化调用)

    PyInt_FromLong()返回指向内部数组的指针,该数组在您的示例中未初始化。因此,您得到一些无效指针并将其传递给Py_Compare()函数会使解释器崩溃

    有关初始化的详细信息,请参见此处:

    至少尝试在test()函数的开头添加“Py_Initialize()”调用

    编辑:

    有趣的是,如果使用以下程序从C运行libtest.test,那么来自GDB的堆栈跟踪是什么:

    #include <dlfcn.h>
    
    typedef int (*fcn)();
    
    int main()
    {
        void* dll = dlopen("libtest.so", RTLD_LAZY);
    
        /* dlerror checks here */
    
        fcn Test = (fcn)dlsym(dll, "test");
    
        Test();
    
        dclose(dll);
    
        return 0;
    }
    
    #包括
    typedef int(*fcn)();
    int main()
    {
    void*dll=dlopen(“libtest.so”,RTLD_-LAZY);
    /*这里有错误检查*/
    fcn测试=(fcn)dlsym(dll,“测试”);
    Test();
    dclose(dll);
    返回0;
    }
    
    编辑2:

  • 编译测试(gcc-odlltest.c-ldl)

  • 运行“gdb dlltest”

  • 在gdb提示符中键入命令“run”

  • 看看它是否崩溃

  • 如果是,请在gdb的提示符中键入回溯

  • 编辑3:

    不清楚坠机地点。尝试在每次printf()调用后添加“fflush(stdout);”以确保错误已被打印出来



    如果“result=-1”出现在基于python的应用程序中,则错误出现在ctypes中,而不是libtest中。因此。

    提供一个显示问题的最小完整示例。您是如何初始化python的?您使用多线程吗?你在检查错误吗?python仍然是初始化的还是您破坏了它?您是否尝试重新加载解释器?请显示完整的最小程序。@Arafangion我试过使用python脚本,也试过使用解释器,同样的问题。但我没有检查错误。我真的不知道该检查什么,对不起,我还是个初学者。如果你想写一个C扩展,为什么要使用
    ctypes
    ?我发现一开始就比较容易。我不是真的想写一个扩展,只是想学习如何做。像这样使用ctypes是错误的吗?请提供一个最小的、完整的示例来说明这个问题。您是如何初始化python的?您使用多线程吗?你在检查错误吗?python仍然是初始化的还是您破坏了它?您是否尝试重新加载解释器?请显示完整的最小程序。@Arafangion我试过使用python脚本,也试过使用解释器,同样的问题。但我没有检查错误。我真的不知道该检查什么,对不起,我还是个初学者。如果你想写一个C扩展,为什么要使用
    ctypes
    ?我发现一开始就比较容易。我不是真的想写一个扩展,只是想学习如何做。像这样使用ctypes错误吗?谢谢你的回答,但是使用Py_Initialize()没有任何区别。我将不得不尝试不使用其他人建议的ctypes。您可以添加“python config--ldflags”和“python config--cflags”的输出吗?我在问题中添加了它们。谢谢。增加了C测试。也许你可以尝试一下,然后转储GDB的输出,看看它为什么会崩溃?再次感谢你,我还是个初学者,现在用GDB调试东西对我来说是不可能的。然而,我试着运行你的C测试,但一开始它不起作用,在搜索了一段时间后,我在我的共享库中使用了带有gcc的
    -lpthread
    (不知道为什么),然后你的测试程序使用了它,但是带有ctypes的python仍然给出了相同的行为。谢谢你的回答,但是使用Py_Initialize()没什么不同。我将不得不尝试不使用其他人建议的ctypes。您可以添加“python config--ldflags”和“python config--cflags”的输出吗?我在问题中添加了它们。谢谢。增加了C测试。也许你可以尝试一下,然后转储GDB的输出,看看它为什么会崩溃?再次感谢你,我还是个初学者,现在用GDB调试东西对我来说是不可能的。然而,我试过了