我正在用Python编写应用程序,其中一部分是用C ++编写的。用boost :: python编写的Python绑定只暴露了一个名为merge_charstrings的函数。我的C ++库崩溃时出现了分段错误,但只有在通过Python访问时才会崩溃 - 并且只有在多次调用该函数时才会崩溃。 segfault本身的位置并不一定意味着Python绑定有问题,但我不能让它在纯C ++演示中崩溃。
函数merge_charstrings有两个参数,两个参数都是包含字符串和数字的列表,例如。
[14, 344, 'hmoveto', 65, 'hlineto', -6, 24, -3, 44, 93, 'vvcurveto', 163, 'vlineto', 113, -70, 48, -98, -52, -59, -13, -35, -55, 'vhcurveto', 28, -52, 'rlineto', 20, 33, 40, 19, 57, 'hhcurveto', 59, 43, -32, -72, 'hvcurveto', -30, 'vlineto', -90, -3, -48, -2, -38, -5, -32, -16, 'rlinecurve', -48, -22, -32, -43, -63, 'vvcurveto', -91, 64, -55, 86, 59, 46, 28, 35, 37, 'vhcurveto', -4, 181, 'rmoveto', -120, 'vlineto', -23, -22, -44, -39, -59, 'hhcurveto', -54, -34, 36, 52, 31, 14, 27, 27, 15, 'hvcurveto', 21, 11, 27, 6, 41, 1, 'rrcurveto', 'endchar']
返回类型相同。这些转换为C ++类型std :: vector< CsToken>,其中CsToken是我自己的类之一。
这是Python绑定代码。转换器基于this tutorial。
#include <boost/python.hpp>
#include <CsMerge.hpp>
namespace py = boost::python;
using namespace csmerge;
struct CsTokenFromPythonNumber {
static void* convertible(PyObject* objPtr) {
if (!PyLong_Check(objPtr) && !PyFloat_Check(objPtr)) {
return NULL;
}
return objPtr;
}
static void construct(PyObject* objPtr,
py::converter::rvalue_from_python_stage1_data* data) {
typedef py::converter::rvalue_from_python_storage<CsToken> rval_t;
double value = PyFloat_AsDouble(objPtr);
void* storage = reinterpret_cast<rval_t*>(data)->storage.bytes;
new (storage) CsToken(value);
data->convertible = storage;
}
};
struct CsTokenFromPythonString {
static void* convertible(PyObject* objPtr) {
if (!PyUnicode_Check(objPtr)) {
return NULL;
}
return objPtr;
}
static void construct(PyObject* objPtr,
py::converter::rvalue_from_python_stage1_data* data) {
typedef py::converter::rvalue_from_python_storage<CsToken> rval_t;
long int size;
const char* value = PyUnicode_AsUTF8AndSize(objPtr, &size);
assert(value);
void* storage = reinterpret_cast<rval_t*>(data)->storage.bytes;
new (storage) CsToken(std::string(value, size));
data->convertible = storage;
}
};
static py::list mergeCharstrings_helper(py::list& cs1Tokens, py::list& cs2Tokens) {
Charstring cs1;
for (int i = 0; i < py::len(cs1Tokens); ++i) {
cs1.push_back(py::extract<CsToken>(cs1Tokens[i]));
}
Charstring cs2;
for (int i = 0; i < py::len(cs2Tokens); ++i) {
cs2.push_back(py::extract<CsToken>(cs2Tokens[i]));
}
Charstring merged = mergeCharstrings(cs1, cs2);
py::list result;
for (const CsToken& tok : merged) {
switch (tok.type) {
case PS_OPERATOR:
result.append(tok.str);
break;
case PS_OPERAND:
result.append(tok.num);
break;
}
}
return result;
}
static void translateException(const CsMergeException& ex) {
PyErr_SetString(PyExc_RuntimeWarning, ex.what());
}
BOOST_PYTHON_MODULE(_pycsmerge) {
py::def("initialise", &csmerge::initialise);
py::def("merge_charstrings", &mergeCharstrings_helper);
py::class_<CsToken>("CsToken", py::init<int>())
.def(py::init<const std::string&>())
.def("__eq__", &CsToken::operator==)
.def("__ne__", &CsToken::operator!=);
py::converter::registry::push_back(
&CsTokenFromPythonNumber::convertible,
&CsTokenFromPythonNumber::construct,
py::type_id<CsToken>());
py::converter::registry::push_back(
&CsTokenFromPythonString::convertible,
&CsTokenFromPythonString::construct,
py::type_id<CsToken>());
py::register_exception_translator<CsMergeException>(&translateException);
}
很可能这个bug根本不在Python绑定中,因为段错误经常偶尔出现,但Valgrind报告纯C ++演示没有错误,但在Python演示中有很多错误。
如果我只调用merge_charstrings一次,Python演示永远不会崩溃。如果我把它叫两次,它大部分时间都会崩溃。任何超过两次,它几乎总会崩溃。
from pycsmerge import *
if __name__ == '__main__':
glyph = [
472, 368, 'rmoveto', -133, 225, 258, 66, -589, -66, 257, -225, -133, -66, 133, -302, 74, 302, 133, 'hlineto', 'endchar'
]
watermark = [
0, -237, 'rmoveto', 28.3625, 0, 'rlineto', 274.1375, 425.96466584292557, 'rlineto', 274.13750000000005, -425.96466584292557, 'rlineto', 28.362499999999955, 0, 'rlineto', -288.31875, 448.0, 'rlineto', 288.31875, 448.0, 'rlineto', -28.362499999999955, 0, 'rlineto', -274.13750000000005, -425.96466584292557, 'rlineto', -274.1375, 425.96466584292557, 'rlineto', -28.3625, 0, 'rlineto', 288.31875, -448.0, 'rlineto', -288.31875, -448.0, 'rlineto', 0, 237, 'rmoveto'
]
glyph2 = [
478, 899, 'rmoveto', 53, -172, 'rlineto', 62, 'hlineto', -39, 172, 'rlineto', -548, -240, 'rmoveto', 337, -662, 'rlineto', 54, 'hlineto', 49, 123, 60, 86, 54, 68, 54, -71, 61, -85, 49, -121, 'rrcurveto', 55, 'hlineto', 326, 662, 'rlineto', -82, 'hlineto', -271, -559, 'rlineto', -2, 'hlineto', -39, 93, -55, 73, -51, 63, 'rrcurveto', 60, 71, 46, 61, 81, 'vvcurveto', 88, -64, 56, -87, -87, -65, -56, -89, -79, 46, -58, 61, -75, 'vhcurveto', -50, -62, -55, -74, -38, -93, 'rrcurveto', -2, 'hlineto', -281, 559, 'rlineto', 470, -37, 'rmoveto', 45, 32, -30, -55, -51, -32, -48, -44, -55, 'hvcurveto', -45, 56, -33, 50, 49, 'vvcurveto', 54, 33, 30, 44, 'vhcurveto', 'endchar'
]
watermark2 = [
0, -237, 'rmoveto', 28.3625, 0, 'rlineto', 526.6375, 436.2526262264391, 'rlineto', 526.6375, -436.2526262264391, 'rlineto', 28.362499999999955, 0, 'rlineto', -540.81875, 448.0, 'rlineto', 540.81875, 448.0, 'rlineto', -28.362499999999955, 0, 'rlineto', -526.6375, -436.2526262264391, 'rlineto', -526.6375, 436.2526262264391, 'rlineto', -28.3625, 0, 'rlineto', 540.81875, -448.0, 'rlineto', -540.81875, -448.0, 'rlineto', 0, 237, 'rmoveto'
]
res1 = merge_charstrings(glyph, watermark)
res2 = merge_charstrings(glyph2, watermark2)
print(res1)
print(res2)
堆栈跟踪如下:
#0 0x00007ffff647dcd1 in __gmpq_get_d ()
from /usr/lib/x86_64-linux-gnu/libgmp.so.10
#1 0x00007ffff6766cd6 in CGAL::_Bezier_x_monotone_2<CGAL::Cartesian<CORE::BigRat>, CGAL::Cartesian<CORE::Expr>, CGAL::CORE_algebraic_number_traits, CGAL::Bezier_bounding_rational_traits<CGAL::Cartesian<CORE::BigRat> > >::parameter_range() const ()
from /home/rob/python_envs/dfb/lib/python3.4/site-packages/_pycsmerge.so
#2 0x00007ffff675720e in csmerge::geometry::cubicBezierFromXMonoSection(CGAL::_Bezier_x_monotone_2<CGAL::Cartesian<CORE::BigRat>, CGAL::Cartesian<CORE::Expr>, CGAL::CORE_algebraic_number_traits, CGAL::Bezier_bounding_rational_traits<CGAL::Cartesian<CORE::BigRat> > > const&) ()
from /home/rob/python_envs/dfb/lib/python3.4/site-packages/_pycsmerge.so
#3 0x00007ffff6757797 in csmerge::geometry::toPath(CGAL::General_polygon_2<CGAL::Arr_Bezier_curve_traits_2<CGAL::Cartesian<CORE::BigRat>, CGAL::Cartesian<CORE::Expr>, CGAL::CORE_algebraic_number_traits, CGAL::Bezier_bounding_rational_traits<CGAL::Cartesian<CORE::BigRat> > > > const&) ()
from /home/rob/python_envs/dfb/lib/python3.4/site-packages/_pycsmerge.so
#4 0x00007ffff6757963 in csmerge::geometry::toPathList(std::vector<CGAL::General_polygon_with_holes_2<CGAL::General_polygon_2<CGAL::Arr_Bezier_curve_traits_2<CGAL::Cartesian<CORE::BigRat>, CGAL::Cartesian<CORE::Expr>, CGAL::CORE_algebraic_number_traits, CGAL::Bezier_bounding_rational_traits<CGAL::Cartesian<CORE::BigRat> > > > >, std::allocator<CGAL::General_polygon_with_holes_2<CGAL::General_polygon_2<CGAL::Arr_Bezier_curve_traits_2<CGAL::Cartesian<CORE::BigRat>, CGAL::Carte---Type <return> to continue, or q <return> to quit---
sian<CORE::Expr>, CGAL::CORE_algebraic_number_traits, CGAL::Bezier_bounding_rational_traits<CGAL::Cartesian<CORE::BigRat> > > > > > > const&) ()
from /home/rob/python_envs/dfb/lib/python3.4/site-packages/_pycsmerge.so
#5 0x00007ffff6759200 in csmerge::geometry::Path::computeUnion(std::vector<csmerge::geometry::Path, std::allocator<csmerge::geometry::Path> > const&, std::vector<csmerge::geometry::Path, std::allocator<csmerge::geometry::Path> > const&)
() from /home/rob/python_envs/dfb/lib/python3.4/site-packages/_pycsmerge.so
#6 0x00007ffff675274e in csmerge::mergeCharstrings(std::vector<csmerge::CsToken, std::allocator<csmerge::CsToken> > const&, std::vector<csmerge::CsToken, std::allocator<csmerge::CsToken> > const&) ()
from /home/rob/python_envs/dfb/lib/python3.4/site-packages/_pycsmerge.so
#7 0x00007ffff674c02a in mergeCharstrings_helper(boost::python::list&, boost::python::list&) ()
from /home/rob/python_envs/dfb/lib/python3.4/site-packages/_pycsmerge.so
#8 0x00007ffff674d542 in boost::python::objects::caller_py_function_impl<boost::python::detail::caller<boost::python::list (*)(boost::python::list&, boost::python::list&), boost::python::default_call_policies, boost::mpl::vector3<boost::python::list, boost::python::list&, boost::python::list&> > >::operator()(_object*, _object*) ()
from /home/rob/python_envs/dfb/lib/python3.4/site-packages/_pycsmerge.so
#9 0x00007ffff623613a in boost::python::objects::function::call(_object*, _object*) const () from /usr/lib/x86_64-linux-gnu/libboost_python-py34.so.1.54.0
#10 0x00007ffff62364a8 in ?? ()
---Type <return> to continue, or q <return> to quit---
from /usr/lib/x86_64-linux-gnu/libboost_python-py34.so.1.54.0
#11 0x00007ffff6240953 in boost::python::detail::exception_handler::operator()(boost::function0<void> const&) const ()
from /usr/lib/x86_64-linux-gnu/libboost_python-py34.so.1.54.0
#12 0x00007ffff674d443 in boost::detail::function::function_obj_invoker2<boost::_bi::bind_t<bool, boost::python::detail::translate_exception<csmerge::CsMergeException, void (*)(csmerge::CsMergeException const&)>, boost::_bi::list3<boost::arg<1>, boost::arg<2>, boost::_bi::value<void (*)(csmerge::CsMergeException const&)> > >, bool, boost::python::detail::exception_handler const&, boost::function0<void> const&>::invoke(boost::detail::function::function_buffer&, boost::python::detail::exception_handler const&, boost::function0<void> const&) ()
from /home/rob/python_envs/dfb/lib/python3.4/site-packages/_pycsmerge.so
#13 0x00007ffff624071d in boost::python::handle_exception_impl(boost::function0<void>) () from /usr/lib/x86_64-linux-gnu/libboost_python-py34.so.1.54.0
#14 0x00007ffff6234db3 in ?? ()
from /usr/lib/x86_64-linux-gnu/libboost_python-py34.so.1.54.0
#15 0x000000000051c577 in PyEval_EvalFrameEx ()
#16 0x0000000000487164 in PyEval_EvalCode ()
#17 0x000000000056be90 in ?? ()
#18 0x000000000047b1c3 in PyRun_FileExFlags ()
#19 0x000000000047b5a0 in PyRun_SimpleFileExFlags ()
#20 0x00000000005c0b33 in Py_Main ()
#21 0x000000000047dbc1 in main ()
我很感激任何帮助。感谢