首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Python时的奇怪内存行为

使用Python时的奇怪内存行为
EN

Stack Overflow用户
提问于 2018-02-22 09:30:39
回答 1查看 184关注 0票数 1

我试图在C++库上使用Python实现Python包装器。我需要实现转换,以便在Python和C++中使用对象。我在过去已经这样做了,但我有一个错误,我真的有一个困难的时间。

我有一个非常基本的测试功能:

代码语言:javascript
复制
PyObject* convert_to_python() {
    std::cout << "Convert to PyObject" << std::endl;
    long int a = 20;
    PyObject* py_a = PyInt_FromLong(a);
    std::cout << "Convert to PyObject ok" << std::endl;
    return py_a;
}

我在一个GoogleTest宏中调用这个函数:

代码语言:javascript
复制
TEST(Wrapper, ConvertTest) {
    PyObject *py_m = convert_to_python();
}

我的产出是:

代码语言:javascript
复制
Convert to PyObject
Segmentation fault (core dumped)

我还对此进行了大胆的研究:

代码语言:javascript
复制
valgrind --tool=memcheck --track-origins=yes --leak-check=full ./my_convert

但它并没有给我多少信息:

代码语言:javascript
复制
Invalid read of size 8
==19030==    at 0x4F70A7B: PyInt_FromLong (in /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0)
==19030==    by 0x541E6BF: _object* pysmud_from<float>(smu::Matrix<float, 0, 0>&) (smu_type_conversions.cpp:308)
==19030==    by 0x43A144: (anonymous namespace)::Wrapper_ConvertMatrix_Test::Body() (test_wrapper.cpp:12)
==19030==    by 0x43A0C6: (anonymous namespace)::Wrapper_ConvertMatrix_Test::TestBody() (test_wrapper.cpp:10)
==19030==    by 0x465B4D: void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (gtest.cc:2078)
==19030==    by 0x460684: void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (gtest.cc:2114)
==19030==    by 0x444C05: testing::Test::Run() (gtest.cc:2151)
==19030==    by 0x4454C9: testing::TestInfo::Run() (gtest.cc:2326)
==19030==    by 0x445BEA: testing::TestCase::Run() (gtest.cc:2444)
==19030==    by 0x44CF41: testing::internal::UnitTestImpl::RunAllTests() (gtest.cc:4315)
==19030==    by 0x46712C: bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (gtest.cc:2078)
==19030==    by 0x461532: bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) (gtest.cc:2114)
==19030==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

我认为这段代码应该有效,但我无法理解我所写的东西有什么问题。我是否错误地包含或链接了Python文件和库?

编辑:不提供错误

代码语言:javascript
复制
#include <Python.h>

PyObject* convert_long_int(long int a) {
  PyObject *ret = PyInt_FromLong(a);
  return ret;
}

int main(void) {
  long int a = 65454984;
  PyObject *pya = convert_long_int(a);
  return 0;
}

gcc -o wraptest -I/usr/include/python2.7 wraptest.c -L/usr/lib/x86_64-linux-gnu/ -lpython2.7编译

初始化是做什么的?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-02-22 10:03:31

如果省略初始化,我可以确认Ubuntu16.04和Python2.7上的分段错误。

看看在另一个应用程序中嵌入Python,有个例子

代码语言:javascript
复制
#include <Python.h>

int
main(int argc, char *argv[])
{
  Py_SetProgramName(argv[0]);  /* optional but recommended */
  Py_Initialize();
  PyRun_SimpleString("from time import time,ctime\n"
                     "print 'Today is',ctime(time())\n");
  Py_Finalize();
  return 0;
}

所以当我做一个等价的最小主值时

代码语言:javascript
复制
int main()
{
    Py_Initialize();
    PyObject *p = convert_to_python();
    Py_Finalize();
    return 0;
}

它在没有碰撞的情况下工作。

这两个例子的区别是

代码语言:javascript
复制
long int a = 20;

代码语言:javascript
复制
long int a = 65454984;

我想,这跟FromLong(长ival)有关

当前实现为-5到256之间的所有整数保留了一个整数对象数组,当在该范围内创建int时,实际上只需要返回对现有对象的引用。

可能Python尝试访问未初始化的指针或内存范围而不进行初始化。

当我使用a = 256更改示例时,它会崩溃。使用a = 257,它没有。

查看cpython/Objects/intopject.c:79,您可以看到一个指针数组

代码语言:javascript
复制
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];

在下面的FromLong(长ival)中访问

代码语言:javascript
复制
v = small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);

但是没有从Init(无效)初始化

代码语言:javascript
复制
for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++) {
    if (!free_list && (free_list = fill_free_list()) == NULL)
        return 0;
    /* PyObject_New is inlined */
    v = free_list;
    free_list = (PyIntObject *)Py_TYPE(v);
    (void)PyObject_INIT(v, &PyInt_Type);
    v->ob_ival = ival;
    small_ints[ival + NSMALLNEGINTS] = v;
}

这些指针都是NULL,导致崩溃。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48923810

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档