【问题标题】:Segmentation fault when importing a C++ shared object in Python在 Python 中导入 C++ 共享对象时出现分段错误
【发布时间】:2021-06-03 09:53:14
【问题描述】:

我有以下共享对象:

MyLib.cpp

#include <iostream>

class MyClass
{
 public:
 MyClass(){}

 void function()
 {
  std::cout << "hello" << std::endl;
  //var = 10;
 }

 private:

 int var;

};



extern "C" {
 MyClass* create()
 {
  return new MyClass();
 }


 void func(MyClass* myclass)
 {
  myclass->function();
 }

}

我编译时使用:g++ -fPIC -shared -o MyLib.so MyLib.cpp

然后我将它与以下 Python 脚本一起使用:

script.py

import ctypes

lib = ctypes.cdll.LoadLibrary("./MyLib.so")

MyClass = lib.create()
lib.func(MyClass)

像这样,它可以完美运行,但是如果我取消注释 //var = 10; 行,Python 会出现分段错误(Python 3.8)。每次对象MyClass 对其局部变量之一进行更改时都会发生这种情况(构造函数内部除外,它在其中工作)。看起来变量var 的地址错误,访问时出现分段错误。我尝试在没有任何更改的情况下为function 使用关键字“virtual”,并尝试使用 dlfcn 在另一个 C++ 程序中导入共享对象,效果很好。知道有什么问题吗?

【问题讨论】:

  • 除此之外没有回答您的问题:由于create()func() 的用户并不真正了解或关心他们使用的对象的类型。接口可能应该返回void* 作为这方面的指标。 func() 函数可以在调用方法之前将其转换回正确的类型。

标签: python c++ shared-objects


【解决方案1】:

指针不一样:

extern "C" {
    MyClass* create()
    {
        MyClass* myclass = new MyClass();
        std::cerr << "Returning: " << myclass << "\n";
        return myclass;
    }


    void func(MyClass* myclass)
    {
        std::cerr << "Calling:   " << myclass << "\n";
        myclass->function();
    }

}

跑步我得到:

Returning: 0x7faab9c06580
Calling:   0xffffffffb9c06580

似乎某处存在符号扩展问题。

您需要告诉 python 传递的对象的类型,否则它会认为它们是 int 并且会发生令人讨厌的事情:

import ctypes

lib = ctypes.cdll.LoadLibrary("./MyLib.so")
lib.create.restype = ctypes.c_void_p;
lib.func.argtypes = [ ctypes.c_void_p ];


MyClass = lib.create();
lib.func(MyClass)

【讨论】:

  • 非常好,谢谢!确实这解决了问题,但是我真的不明白到底发生了什么令人讨厌的事情,以及为什么带有错误指针的函数在打印文本时起作用。
  • @Flav 它仅在打印时起作用,因为未使用指针。您调用了一个函数(传递“this”参数)但您从未使用“this”,因此代码没有问题。当您尝试使用“this”访问成员变量“var”时,它是无效的并指向内存中的某个随机位置,当您尝试写入它时会导致段错误。
  • 讨厌的东西看起来像符号扩展。将负数放入 8 位变量中。现在将该 8 位变量复制到 16 位变量。您不能只复制 8 位,因为这会使结果为 16 位正值。您需要对值进行符号扩展以将其存储在 16 位值中(请注意,上面的所有最高位都转换为 f 这是符号扩展)。当您在不同大小的变量之间移动有符号值时,就会发生这种情况。
  • 注意:整数是有符号的。但是指针不是有符号值。因此,扩展它们的符号对您更改指针的值没有任何用处。有效地使其指向一个完全不同的页面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-19
  • 1970-01-01
  • 2016-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多