抛出异常:读取访问冲突。 **bp** 为 0xFFFFFFFFFFFFFFFF

Posted

技术标签:

【中文标题】抛出异常:读取访问冲突。 **bp** 为 0xFFFFFFFFFFFFFFFF【英文标题】:Exception thrown: read access violation. **bp** was 0xFFFFFFFFFFFFFFFF 【发布时间】:2018-11-14 14:07:09 【问题描述】:

我创建了一个项目并想在 C++ 项目中获取 numpy 数组。我可以获得正确的数字,但它报告读取访问冲突。这是我的名为 main.py 的 python 代码

import numpy as np
import tensorflow as tf

class PyInterface(object):
    def __init__(self):
        self.X = None
        self.Y = None

    def generate_np_uint8(self):
        np_array = np.random.randint(low=0, high=255, size=(2,2,2),dtype=np.uint8);
        print("Python, uint8:", np_array)
        return np_array

    def generate_np_float32(self):
        np_array = np.random.rand(2,2,2).astype(np.float32)
        print("Python, float:", np_array)
        return np_array


if __name__ == '__main__':
    py = PyInterface();
    py.generate_np_uint8();
    py.generate_np_float32();

这是我用于扩展 python 的 C++ 代码

public:
float * CppPythonHandler::get_float() 
    return generate_np_float32();

private:
float * CppPythonHandler::generate_np_float32() 
    const int ND3;
    float *c_out = new float[8];
    PyArrayObject *np_ret;
    PyObject* np_array = PyObject_CallMethod(interface, (const char*)"generate_np_float32", NULL, NULL);
    if (np_array) 
        np_ret = reinterpret_cast<PyArrayObject*>(np_array);
        if (PyArray_NDIM(np_ret) != ND) 
            std::cout << "Function returned with wrong dimension" << std::endl;
            Py_DECREF(np_array);
            Py_DECREF(np_ret);
            return c_out;
        
        c_out[0] = *((float *)PyArray_GETPTR3(np_ret, 0, 0, 0));
        c_out[1] = *((float *)PyArray_GETPTR3(np_ret, 0, 0, 1));
        c_out[2] = *((float *)PyArray_GETPTR3(np_ret, 0, 1, 0));
        c_out[3] = *((float *)PyArray_GETPTR3(np_ret, 0, 1, 1));
        c_out[4] = *((float *)PyArray_GETPTR3(np_ret, 1, 0, 0));
        c_out[5] = *((float *)PyArray_GETPTR3(np_ret, 1, 0, 1));
        c_out[6] = *((float *)PyArray_GETPTR3(np_ret, 1, 1, 0));
        c_out[7] = *((float *)PyArray_GETPTR3(np_ret, 1, 1, 1));
        for (int i = 0; i < 8; ++i) 
            std::cout << c_out[i] << " ";
        
        std::cout << std::endl;
        Py_DECREF(np_ret);
        Py_DECREF(np_array);
        return c_out;
    
    else
        PyErr_Print();
        Py_DECREF(np_array);
        Py_DECREF(np_ret);
        return c_out;
    

这是我的 main.cpp

static int numargs=0;

static PyObject*
emb_numargs(PyObject *self, PyObject *args)

    if(!PyArg_ParseTuple(args, ":numargs"))
        return NULL;
    return PyLong_FromLong(numargs);


static PyMethodDef EmbMethods[] = 
    "numargs", emb_numargs, METH_VARARGS,
     "Return the number of arguments received by the process.",
    NULL, NULL, 0, NULL
;

static PyModuleDef EmbModule = 
    PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods,
    NULL, NULL, NULL, NULL
;

static PyObject*
PyInit_emb(void)

    return PyModule_Create(&EmbModule);


int main(int argc, char *argv[]) 
    if (argc < 1) 
        fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
        return 1;
    

    numargs = argc;
    PyImport_AppendInittab("emb", &PyInit_emb);

    Py_Initialize();        // initialize python interpreter
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("if not hasattr(sys, 'argv'):\n    sys.argv=['']");
    PyRun_SimpleString("sys.path.insert(0, \"./\")");
    PyRun_SimpleString("sys.path.insert(0, \"./venv/Lib\")");
    PyRun_SimpleString("sys.path.insert(0, \"./venv/Lib/site-packages\")");

    // instance cpp interface object
    CppPythonHandler * pInter = new CppPythonHandler("main", "PyInterface");
    // unsigned char * np_uint8 = pInter->get_uint8();
    float * np_float = pInter->get_float();

    std::cout<<"End test"<<std::endl;
    // delete []pInter;

    if (Py_FinalizeEx() < 0) 
        std::cout << "Fails to release" << std::endl;
        return 120;
    
    system("pause");
    return 0;

通过终端我可以看到我可以从 python 脚本中获取正确的值

从调用堆栈中我知道它在 PyObject_Alloc 中损坏了

但我仍然不知道到底是什么问题。谁能告诉我

编辑1: 这是我的构造函数

CppPythonHandler::CppPythonHandler(const char* pModuleName, const char* pClassName) 
    interfaceModule = NULL;
    interfaceClass = NULL;
    interface = NULL;
    interfaceModule = PyImport_ImportModule(pModuleName);
    if (interfaceModule == NULL) 
        PyErr_Print();
        fprintf(stderr,"Fails to import the module.\n");
        Py_DECREF(interfaceModule);
    
    else
        // import interface class
        interfaceClass = PyObject_GetAttrString(interfaceModule, pClassName);
        if (interfaceClass && PyCallable_Check(interfaceClass)) 

            // NULL represents no args
            interface = PyObject_CallObject(interfaceClass, NULL);
            Py_DECREF(interfaceClass);
            Py_DECREF(interfaceModule);
            if(interface == NULL)
                fprintf(stderr,"Fails to instance interface.\n");
                Py_DECREF(interface);
            
            std::cout<<"Initailization done"<<std::endl;
        
        else
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr,"Fails to import the class.\n");
            Py_DECREF(interfaceClass);
            Py_DECREF(interfaceModule);
        
    

interfaceModule、interfaceClass 和 interface 是私有的 PyObject*

编辑2: 这里是 PyObject_Alloc 的本地参数

【问题讨论】:

【参考方案1】:

我遇到了同样的错误信息,但几乎是偶然地设法修复它。

总结: 这似乎是由 PyObject* 的引用计数不正确引起的。 发生错误时使用的 PyObjects 不一定是引用计数不正确的对象! 如果您还没有阅读 https://docs.python.org/3/c-api/intro.html#objects-types-and-reference-counts 可能会有所帮助。

在我的例子中,我的 C++ 正在从从 python 函数获得的 PyObject 列表中读取项目。但是,当从列表中读取这些项目时,它们的引用计数没有增加,因为我调用的是 PyList_GetItem() 而不是 PySequence_GetItem()。调试起来很痛苦,因为错误是从运行 PyObject_CallFunction() 的完全不相关的代码部分引发的。

希望这会有所帮助!

【讨论】:

以上是关于抛出异常:读取访问冲突。 **bp** 为 0xFFFFFFFFFFFFFFFF的主要内容,如果未能解决你的问题,请参考以下文章

C++ Int 似乎没有初始化并抛出异常:读取访问冲突

抛出未处理的异常:读取访问冲突。 x 是 0x20B4112

抛出异常:读取访问冲突。这是0xBF13D000

为什么调试器会抛出“读取访问冲突。这是nullptr”例外吗?

C++ Battle4Zion 项目抛出未处理的异常:读取访问冲突。 **this** 是 nullptr。发生了

DLL代理调用LoadLibrary导致异常:访问冲突读取位置0x00000250