调用 python3 操作 Py_buffer 的扩展模块函数时获取 SIGSEGV
Getting a SIGSEGV when calling python3 extension module function operating a Py_buffer
我正在研究 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
的字符,释放缓冲区,并 returns 对表示整数 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 参数时使用了错误的格式说明符。
y#
要求将缓冲区的长度也传递给 PyArg_ParseTuple
,我没有这样做。另请注意,#
变体采用只读缓冲区。
y*
按预期工作。
这很好,但它仍然不能解释为什么 python 版本之一崩溃而另一个没有。
我正在研究 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
的字符,释放缓冲区,并 returns 对表示整数 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 参数时使用了错误的格式说明符。
y#
要求将缓冲区的长度也传递给 PyArg_ParseTuple
,我没有这样做。另请注意,#
变体采用只读缓冲区。
y*
按预期工作。
这很好,但它仍然不能解释为什么 python 版本之一崩溃而另一个没有。