首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用PyObject库从C函数返回PyTCC时如何修复“访问冲突”错误

使用PyObject库从C函数返回PyTCC时如何修复“访问冲突”错误
EN

Stack Overflow用户
提问于 2019-04-09 18:11:44
回答 2查看 1.4K关注 0票数 0

我正在使用一个包装LibTCC的Python库,名为PyTCC

我正在试验用Python编译JIT代码的方法。问题是,当调用一个函数时,我可以正确地返回普通C数据类型,但是当返回任何PyObject *时,我会得到一个“访问冲突”错误。

如我的代码示例所示,我已经确保代码可以从PyTCC执行。这也意味着代码示例正在成功编译。

代码语言:javascript
运行
复制
import ctypes, pytcc

program = b"""
#include "Python.h"

/* Cannot return 3 due to access violation */
PyObject * pop(PyObject * self, PyObject * args, PyObject * kwargs) {
    // Cannot return *any* Python object
    return PyLong_FromLong(3);
}

int foobar() { return 3; }  // Returns 3 just fine

// Needed to appease TCC:
int main() { }
"""

jit_code = pytcc.TCCState()
jit_code.add_include_path('C:/Python37/include')
jit_code.add_library_path('C:/Python37')
jit_code.add_library('python37')
jit_code.compile_string(program)
jit_code.relocate()

foobar_proto = ctypes.CFUNCTYPE(ctypes.c_int)
foobar = foobar_proto(jit_code.get_symbol('foobar'))

print(f'It works: {foobar()}')

pop_proto = ctypes.CFUNCTYPE(ctypes.c_voidp)
pop = pop_proto(jit_code.get_symbol('pop'))

print('But this does not for some reason:')
print(pop())
print('Never gets here due to access violation :(')

程序的输出应该是:

代码语言:javascript
运行
复制
It works: 3
But this does not for some reason:
3
Never gets here due to access violation :(

但是,相反,我得到了一个确切的错误:

代码语言:javascript
运行
复制
It works: 3
But this does not for some reason:
Traceback (most recent call last):
  File "fails.py", line 40, in <module>
    print(pop())
OSError: exception: access violation writing 0x00000000FFC000E9
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-09 20:51:58

很可能是因为创建对象时没有GIL。返回类型也有问题。ctypes.c_voidp告诉python要把它当作int而不是PyObject,所以如果不是因为访问冲突,那么只能看到值指针本身而不是它所指向的。

尝试:

代码语言:javascript
运行
复制
    PyObject * pop() {
    PyGILState_STATE gstate;
    gstate = PyGILState_Ensure();
    PyObject* obj = PyLong_FromLong(10);
    PyGILState_Release(gstate);
    return obj;
}

和开关

pop_proto = ctypes.CFUNCTYPE(ctypes.c_voidp)

pop_proto = ctypes.CFUNCTYPE(ctypes.py_object)

运行的输出(将pyobject中的值从3更改为10,只需显示它已完成)

代码语言:javascript
运行
复制
It works: 3
But this does not for some reason:
10
Never gets here due to access violation :(
票数 0
EN

Stack Overflow用户

发布于 2019-04-09 21:06:20

没有使用PyTCC,但是代码有问题。

根据) (是我的):

这个类的实例的行为类似于CDLL实例,只是函数调用期间不会释放Python,函数执行之后将检查Python标志。如果设置了错误标志,则会引发Python异常。 因此,只适用于直接调用Python函数

备注:CFUNCTYPE代表CDLL,与PYFUNCTYPE表示PyDLL相同。

因此,在pop_proto中,您应该用ctypes.PyFUNCTYPE替换ctypes.CFUNCTYPE (请注意,您在c_voidp中有一个错误)。

接下来,同一页声明对于PyObject* (C),应该使用py_object (Python)。所以:

代码语言:javascript
运行
复制
pop_proto = ctypes.PyFUNCTYPE(ctypes.py_object)

如果您想要严谨,就必须在原型中包含参数,这将使代码看起来更加复杂,但是对于这种特殊情况(它们被忽略),它不是强制性的:

代码语言:javascript
运行
复制
pop_proto = ctypes.PyFUNCTYPE(ctypes.py_object, ctypes.py_object, ctypes.py_object, ctypes.py_object)

下面是PyObject *PyBytes_Repr(PyObject *obj, int smartquotes)的一个示例(以“老式”的方式调用C函数):

CFATI@cfATI-5510-0:C:\WINDOWS\system32 32> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe“Python3.7.3 (v3.7.3:ef4ec6ed12,22:22:05) MSC v.1916 64位(AMD64) on win32类型”帮助“、”版权“、”信用“或”许可“以获取更多信息。>>> >>> import sys >>> python_dll_name = os.path.join(os.path.dirname(sys.executable),"python“+ str(sys.version_info.major) + str(sys.version_info.minor) + ".dll") >>> python_dll_name >>> >>> python_dll = ctypes.PyDLL(python_dll_name) >>> >>> pybytes_repr_proto =ctypes.PYFUNCTYPE(Python_dll) >>> >>> b= b"abcd“>>> >>> reprb = pybytes_repr(b,0) >>> reprb "b'abcd'”

您还可以检查[SO]:如何转换指向Python类实例的ctype指针(@CristiFati的答案)

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

https://stackoverflow.com/questions/55598839

复制
相关文章

相似问题

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