Python C-API函数调用间传递指针方法及PyCapsule取值崩溃问题
问题原因与解决方案
核心错误点
spam_new函数存在野指针问题:定义了struct spam *pointer变量,但将malloc申请的内存地址赋值给了未声明的state变量,导致pointer始终是野指针,后续spam_init(*pointer, number)直接解引用野指针访问非法内存,最终返回的PyCapsule封装的也是无效指针。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
相关产品推荐
相关产品推荐

