首页 > 解决方案 > 访问冲突写入位置 0x0000000C

问题描述

我正在为一件事而苦苦挣扎。我正在尝试通过注入的 dll 从 python api 调用游戏的函数。它有时有效,但大多会引发错误:

在 Soria2.pl.exe 中的 0x1E07F731 (python27.dll) 处引发异常:0xC0000005:访问冲突写入位置 0x0000000C

以上是来自调试器的日志。

我的代码:

 std::vector<int> mobList()
    {
        PyObject* mod = PyObject_GetAttrString(PyImport_AddModule("player"), "GetCharacterDistance");
        PyObject* mod2 = PyObject_GetAttrString(PyImport_AddModule("chr"), "GetInstanceType");
        PyObject* args = PyTuple_New(1);
        std::vector<int> mobs;
    
        for (int i = 1; i < 100000; i++) {
            try {
                PyTuple_SetItem(args, 0, PyInt_FromLong(i));
                PyObject* mob = PyObject_CallObject(mod, args);
                if (PyInt_AsLong(mob) > 0 && PyInt_AsLong(mob) < 400) {
                    PyObject* enemy = PyObject_CallObject(mod2, args);
                    if (PyInt_AsLong(enemy) == 0) {
                        mobs.push_back(i);
                    }
                    if (enemy != NULL) {
                        Py_DECREF(enemy);
                    }
                }
                if (mob != NULL) {
                    Py_DECREF(mob);
                }
                Py_XDECREF(args);
            }
            catch (int e) {
                std::cout << e << std::endl;
            }
        }
        return mobs;
    }

和有问题的部分:

PyObject* mob = PyObject_CallObject(mod, args);

它有时会起作用,但主要是在随机迭代次数(50k、60k、70k 等)后抛出上述错误。我尝试了一切,但仍然无法弄清楚:/感谢任何帮助。

标签: pythonc++

解决方案


我认为@chi 是对的:

无效 Py_DECREF(PyObject *o)

减少对象 o 的引用计数。对象不能为 NULL;如果您不确定它是否为 NULL,请使用 Py_XDECREF()。如果引用计数达到零,则调用对象类型的释放函数(不能为 NULL)。

无效 Py_XDECREF(PyObject *o)

减少对象 o 的引用计数。对象可能为NULL,这种情况下宏不起作用;否则效果与 Py_DECREF() 相同,同样的警告也适用。

警告

释放函数可以导致任意 Python 代码被调用(例如,当具有del () 方法的类实例被释放时)。虽然此类代码中的异常不会传播,但执行的代码可以自由访问所有 Python 全局变量。这意味着在调用 Py_DECREF() 之前,可以从全局变量访问的任何对象都应该处于一致状态。例如,从列表中删除对象的代码应将对已删除对象的引用复制到临时变量中,更新列表数据结构,然后为临时变量调用 Py_DECREF()。

你应该Py_XDECREF(args)for循环之后。

重读文档我看到了一个例子:

arglist = Py_BuildValue("(l)", eventcode);
result = PyObject_CallObject(my_callback, arglist);
Py_DECREF(arglist);
if (result == NULL)
    return NULL; /* Pass error back */
/* Here maybe use the result */
Py_DECREF(result);

带有明确的注释:

请注意 Py_DECREF(arglist) 在调用之后、错误检查之前的位置!

因此,正如您在其中一条评论中所说,您可以args在循环内移动创作。


推荐阅读