Boost.Python + OpenGL 分段错误
我有一个用 Boost.Python 编写的(几乎)完美运行的 C++ 代码。它包装了一个基于共享指针的 3 或 4 个类的结构层次结构,没有什么非常复杂的(即类 A 有一个类 B 实例指针的 std::vector 等),顶级包称为 foo。
前段时间我决定使用 PyOpenGL 将可视化添加到项目中。所以现在,每当我在 import foo
之前导入 OpenGL 时,我都会在 C++ 代码中遇到分段错误(例如,当我迭代一系列对象及其对象时)子对象。)
我最好的假设是OpenGL以某种方式替代了内存分配函数或者做了一些类似的邪恶的事情。任何人都可以阐明这一情况吗?我会根据要求尝试提供更多详细信息,但整个事情似乎相当混乱。
根据要求,隔离测试用例:
Makefile:
all:
g++ -shared -o foo.so -fPIC \
-I/usr/include/boost-1_37/ -I/usr/include/python2.5 \
-lpython2.5 -lboost_python-1_37 \
foo.cpp
Python 文件:
from OpenGL import *
import foo
b = foo.B()
for i in range(10):
b.elements.append(foo.A())
for e in b.elements:
print e
# Crash here if `from OpenGL import *` is present.
C++ 文件:
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace bp = boost::python;
struct A {
typedef boost::shared_ptr<A> ptr;
};
struct B {
typedef boost::shared_ptr<B> ptr;
std::vector<A::ptr> elements;
};
// Proxies B::elements without converting them
// back and forth between lists.
struct ElementProxy {
static ElementProxy
init(B::ptr b)
{
return ElementProxy(b);
}
ElementProxy(B::ptr b)
: b_(b)
{}
size_t
len()
{
return (*b_).elements.size();
}
A::ptr
getitem(size_t i)
{
if (i >= len()) {
PyErr_SetString(PyExc_IndexError, "Index out of bounds.");
bp::throw_error_already_set();
}
return (*b_).elements[i];
}
void
append(A::ptr e)
{
(*b_).elements.push_back(e);
}
static boost::python::class_<ElementProxy>
wrap()
{
return bp::class_<ElementProxy>("ElementProxy", bp::no_init)
.def("__len__", &ElementProxy::len,
(bp::arg("self")),
"Returns the number of contained elements"
)
.def("__getitem__", &ElementProxy::getitem,
(bp::arg("self"), bp::arg("i")),
"Returns the element at given index"
)
.def("append", &ElementProxy::append,
(bp::arg("self"), bp::arg("element")),
"Appends an element"
)
;
}
private:
B::ptr b_;
};
BOOST_PYTHON_MODULE(foo) {
bp::class_<A, A::ptr, boost::noncopyable>("A") ;
ElementProxy::wrap();
bp::class_<B, B::ptr, boost::noncopyable>("B")
.add_property("elements", &ElementProxy::init) ;
}
I have a (almost) perfectly working C++ code written with Boost.Python. It wraps a shared pointer based structure hierarchy of 3 or 4 classes, nothing terribly complex (i.e. class A has a std::vector of class B instance pointers, etc.), top level package called, say, foo.
Some time ago I decided to add visualization to the project using PyOpenGL. So now, whenever I have import OpenGL
before I have import foo
, I'm getting segmentation faults inside C++ code (such as when I iterate over a sequence of objects and their child objects.)
My best assumption is that OpenGL somehow substitutes memory allocation functions or does something similarly unholy. Any one can shed some light on the situation? I'll try to provide more details on request, but the whole thing seems to be rather chaotic.
On request, isolated test case:
Makefile:
all:
g++ -shared -o foo.so -fPIC \
-I/usr/include/boost-1_37/ -I/usr/include/python2.5 \
-lpython2.5 -lboost_python-1_37 \
foo.cpp
Python file:
from OpenGL import *
import foo
b = foo.B()
for i in range(10):
b.elements.append(foo.A())
for e in b.elements:
print e
# Crash here if `from OpenGL import *` is present.
C++ file:
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace bp = boost::python;
struct A {
typedef boost::shared_ptr<A> ptr;
};
struct B {
typedef boost::shared_ptr<B> ptr;
std::vector<A::ptr> elements;
};
// Proxies B::elements without converting them
// back and forth between lists.
struct ElementProxy {
static ElementProxy
init(B::ptr b)
{
return ElementProxy(b);
}
ElementProxy(B::ptr b)
: b_(b)
{}
size_t
len()
{
return (*b_).elements.size();
}
A::ptr
getitem(size_t i)
{
if (i >= len()) {
PyErr_SetString(PyExc_IndexError, "Index out of bounds.");
bp::throw_error_already_set();
}
return (*b_).elements[i];
}
void
append(A::ptr e)
{
(*b_).elements.push_back(e);
}
static boost::python::class_<ElementProxy>
wrap()
{
return bp::class_<ElementProxy>("ElementProxy", bp::no_init)
.def("__len__", &ElementProxy::len,
(bp::arg("self")),
"Returns the number of contained elements"
)
.def("__getitem__", &ElementProxy::getitem,
(bp::arg("self"), bp::arg("i")),
"Returns the element at given index"
)
.def("append", &ElementProxy::append,
(bp::arg("self"), bp::arg("element")),
"Appends an element"
)
;
}
private:
B::ptr b_;
};
BOOST_PYTHON_MODULE(foo) {
bp::class_<A, A::ptr, boost::noncopyable>("A") ;
ElementProxy::wrap();
bp::class_<B, B::ptr, boost::noncopyable>("B")
.add_property("elements", &ElementProxy::init) ;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您的操作系统是 Linux,您可能会遇到此错误: https:// /bugs.launchpad.net/ubuntu/+source/mesa/+bug/259219。
如果
调用
export LD_PRELOAD=
在启动程序之前 可以修复该问题,就是这样。您需要替换为您机器上的实际路径。类似于 /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/libstdc++.so.6。
该错误仅发生在某些图形驱动程序和发行版中,但它相当普遍。特别是,它在 Ubuntu 11.04 中得到了修复。
If your OS is linux, you might be running into this bug: https://bugs.launchpad.net/ubuntu/+source/mesa/+bug/259219.
If calling
export LD_PRELOAD=<path-to-libstdc++>
before starting your program fixes it, this is it. You need to replace with the actual path on your machine. Something like /usr/lib/gcc/i686-pc-linux-gnu/4.1.2/libstdc++.so.6.
The bug only occurs for some graphics drivers and distributions, but it's quite widespread. In particular, it's fixed in Ubuntu 11.04.