【发布时间】:2020-01-12 17:04:56
【问题描述】:
我正在玩 Python C 扩展模块,我有这个简单的功能:
static PyObject *e_parse_metadata(PyObject *self, PyObject *args) {
Py_buffer buf;
if(!PyArg_ParseTuple(args, "y#", &buf)) {
// interpreter raises exception, we return NULL to indicate failure
return NULL;
}
fprintf(stdout, "extension: %c%c\n\n", *((char *) buf.buf) + 0, *((char*) buf.buf + 1)); // should print "BM"
PyBuffer_Release(&buf);
return PyLong_FromLong(33l);
}
它试图从 Python 中传递给它的参数中获取Py_buffer。然后它将缓冲区的前 2 个字节作为字符显示到stdout,释放缓冲区,并返回对表示整数33 的新PyObject 的引用。
接下来我有这个使用上述函数的 Python 示例:
#!/usr/bin/env python3
import bbmp_utils # my module
with open('./mit.bmp', 'rb') as mit:
if(mit.readable()):
filedata = mit.read()
res = bbmp_utils.parse_metadata(filedata) # call to my function in the extension module
print(res, type(res))
这导致扩展模块成功地将字节流 (extension: BM) 中的前 2 个字节打印到标准输出,但随后终止:fish: “env PYTHONPATH=./build_dbg pyth…” terminated by signal SIGSEGV (Address boundary error)
奇怪的是,直接将bytes 实例传递给我的扩展函数不会导致崩溃,例如
res = bbmp_utils.parse_metadata(mit.read())
为什么第一个示例会导致崩溃而第二个不会?
【问题讨论】:
标签: python buffer cpython python-extensions