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;
   38   39   40   41   42   43   44   45   46   47   48