You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python C-API函数调用间传递指针方法及PyCapsule取值崩溃问题

问题原因与解决方案

核心错误点

  1. spam_new函数存在野指针问题:定义了struct spam *pointer变量,但将malloc申请的内存地址赋值给了未声明的state变量,导致pointer始终是野指针,后续spam_init(*pointer, number)直接解引用野指针访问非法内存,最终返回的PyCapsule封装的也是无效指针。
  2. spam_get函数的PyArg_ParseTuple参数传参错误:格式符O对应的输出参数要求是PyObject **类型,你直接传入了capsule(PyObject*类型,未取地址),导致解析完成后capsule变量存储的是非法内存地址,调用PyCapsule_GetPointer访问非法地址直接崩溃。

修正后的代码

修正spam_new函数

static PyObject *
spam_new (PyObject *self, PyObject *args)
{
    unsigned int number;
    struct spam *pointer;

    if (!PyArg_ParseTuple(args, "I", &number)) {
        return NULL;
    }
    
    // 将malloc结果赋值给pointer变量
    pointer = (struct spam*) malloc(sizeof (struct spam));
    if (pointer == NULL) {
        PyErr_NoMemory();
        return NULL;
    }
    // 传入指针给初始化函数,避免解引用野指针
    spam_init(pointer, number);
    return PyCapsule_New((void*) pointer, "spam", &spam_destroy);
}

修正spam_get函数的参数解析部分

static PyObject *
spam_get (PyObject *self, PyObject *args)
{
    PyObject *capsule, *result;
    void *raw_pointer;
    struct spam *pointer;
    unsigned long long int number;

    // O格式符需要传入PyObject**类型,对capsule取地址
    if (!PyArg_ParseTuple(args, "OK", &capsule, &number)) {
        return NULL;
    }

    printf("[DEBUG] Number: %llu\n", number);
    printf("[DEBUG] Capsule pointer: %p\n", capsule);
    raw_pointer = PyCapsule_GetPointer(capsule, "spam");
    if (raw_pointer == NULL) {
        return NULL;
    }
    pointer = (struct spam*) raw_pointer;
    
    // 剩余业务逻辑
}

优化建议

  • 调用PyCapsule_GetPointer前可以先通过PyCapsule_IsValid(capsule, "spam")校验传入的对象是否是合法的目标capsule,提前抛出类型错误,避免传入其他Python对象导致崩溃。
  • 确保spam_destroy析构函数正确实现了结构体内存释放逻辑,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Mowstyl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 07:15:03