Page 43 - 《软件学报》2026年第7期
P. 43
2728 软件学报 2026 年第 37 卷第 7 期
外部函数实现却尝试接收并解析实际参数. 这种标志位与外部函数实现类型的不一致将导致解释器未传递预期的
参数结构, 引发栈错位或非法内存访问.
类似地, 在代码 7 的测例 2 中, 外部函数实现 wrong_flags_keywords 在外部函数实现的参数中包含关键字参
数 kwargs 并调用 PyArg_ParseTupleAndKeywords 解析关键字参数, 但对应的调用约定位域却不包含 METH_
KEYWORDS 标志, 导致解释器在构造外部函数参数时不会提供关键字参数字典. 这种调用约定与外部函数实现
中解析行为的矛盾, 将导致外部函数访问未定义指针并可能引发运行时崩溃.
代码 7. 调用约定不匹配 (T2.2) 测例.
//测例 1: 使用 METH_NOARGS 标志但尝试接收参数
static PyObject* wrong_flags_noargs(PyObject *self, PyObject *args) {
int value;
//尝试解析参数
if (!PyArg_ParseTuple(args, “i”, &value)) return NULL;
return PyLong_FromLong(value * 2);
}
{“py_wrong_flags_noargs”, (PyCFunction)wrong_flags_noargs, METH_NOARGS, “docstring”}
//测例 2: 使用 METH_VARARGS 标志但尝试解析关键字参数
static PyObject* wrong_flags_keywords(PyObject *self, PyObject *args, PyObject *kwargs) {
int a, b; static char *kwlist[] = {“a”, “b”, NULL};
//尝试解析关键字参数
if (!PyArg_ParseTupleAndKeywords(args, kwargs, “ii”, kwlist, &a, &b)) return NULL;
return PyLong_FromLong(a + b);
}
{“py_wrong_flags_keywords”, (PyCFunction)wrong_flags_keywords, METH_VARARGS, “docstring”}
2.3 异常处理
C/C++缺乏统一的、语言级别的异常处理机制 (C 不具备异常处理机制, C++与 Python 的异常处理机制不完
全兼容), 因此在 Python 的 C/C++外部扩展中, 异常处理依赖基于特定 Python/C API 的显式异常状态管理: 当外部
函数出现逻辑或运行错误时, 必须通过调用 PyErr_SetString、PyErr_SetObject 等 Python/C API 函数设置异常状
态, 且在抛出异常后须显式结束外部控制流返回 Python 侧, Python 的异常处理机制才能检查异常状态并进行处理.
如代码 8 所示, 在外部函数实现 overwrite_error 中, 当 fopen 函数调用失败时通过 Python/C API 函数 PyErr_
SetString 设置异常. 由于 Python/C API 异常不会中断控制流, 因此未立即通过 return 返回会导致异常后非预期控
制流 (E1.1). 外部函数继续执行并在 invalid_condition 为真时再次调用 PyErr_SetString 覆盖原异常, 导致异常重复
抛出 (E1.2), 破坏异常链的完整性.
代码 8. 异常处理错误测例.
//测例: 非预期控制流中覆盖已有异常 (E1.1、E1.2)
static PyObject* overwrite_error(PyObject *self) {
FILE *file = fopen(“nonexistent.txt”, “r”);
if (!file) PyErr_SetString(PyExc_FileNotFoundError, “文件不存在”);
//错误: 非预期控制流
int invalid_condition = 1;

