【问题标题】:Getting a SIGSEGV when calling python3 extension module function operating a Py_buffer调用运行 Py_buffer 的 python3 扩展模块函数时获取 SIGSEGV
【发布时间】: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


    【解决方案1】:

    我在解析 Python 参数时使用了错误的格式说明符。

    y# 要求缓冲区的长度也传递给PyArg_ParseTuple,我没有这样做。另请注意,# 变体假定为只读缓冲区。


    y* 按预期工作。


    这很好,但它仍然不能解释为什么其中一个 python 版本崩溃而另一个没有。

    【讨论】:

      猜你喜欢
      • 2019-12-19
      • 2014-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多