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

传入指针而非地址至PyArg_ParseTuple引发段错误

CPython C API扩展模块中的段错误问题

在基于CPython C API开发Python扩展模块时,遇到一个奇怪的段错误问题(本人C语言仅入门水平)。

正常可运行的模块方法示例:

static PyObject *method_echo(PyObject *self, PyObject *args) {
    long a;
    if(!PyArg_ParseTuple(args, "l", &a)) {
        return NULL;
    }
    printf("Value of the passed variable is: %li\n", a);
    return PyLong_FromLong(a);
}

将变量a声明为指针并传入PyArg_ParseTuple后(其余代码适配指针操作):

long *a;
if(!PyArg_ParseTuple(args, "l", a)) {
    return NULL;
}

会触发段错误。但移除return NULL语句后:

long *a;
PyArg_ParseTuple(args, "l", a);

却能正常运行。即使通过printf确认return NULL分支从未执行,只要传入指针并保留该语句就会触发段错误。


环境信息

  • 系统:macOS 11.6
  • Python版本:python3.9
  • 编译器:clang (clang-1300.0.29.30)

可复现代码

C扩展模块代码(test1_parsepointer.c)

#define PY_SSIZE_T_CLEAN
#include <python3.9/Python.h>

static PyObject *method_parse_ptr1(PyObject *self, PyObject *args) {
    long *a;
    if(!PyArg_ParseTuple(args, "l",a)) {
        printf("PROBLEM ENCOUNTERED\n");
    };
    printf("  ptr-v1: Value of var is: %li\n", *a);
    return PyLong_FromLong(*a);
}

static PyObject *method_parse_ptr2(PyObject *self, PyObject *args) {
    long *a;
    if(!PyArg_ParseTuple(args, "l",a)) {
        return NULL;
    };
    printf("  ptr-v2: Value of var is: %li\n", *a);
    return PyLong_FromLong(*a);
}

static PyObject *method_parse_val(PyObject *self, PyObject *args) {
    long a;
    if(!PyArg_ParseTuple(args, "l",&a)) {
        return NULL;
    };
    printf("     val: Value of var is: %li\n", a);
    return PyLong_FromLong(a);
    
}

static PyMethodDef parseptr_methods[] = {
    {"parse_ptr_v1", method_parse_ptr1, METH_VARARGS, "Parse as pointer, no NULL"},
    {"parse_ptr_v2", method_parse_ptr2, METH_VARARGS, "Parse as pointer, with NULL"},
    {"parse_val", method_parse_val, METH_VARARGS, "Parse as val, with NULL"},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef parsing_ptrs = {
    PyModuleDef_HEAD_INIT,
    "test1_pptr",
    "Testing PyArg_ParseTuple vars as pointers",
    -1,
    parseptr_methods
};

PyMODINIT_FUNC PyInit_test1_pptr(void) {
    return PyModule_Create(&parsing_ptrs);
}

编译命令

clang -shared -undefined dynamic_lookup -o test1_parsepointer.so test1_parsepointer.c

模块引导文件(test1_pptr.py)

def __bootstrap__():
    global __bootstrap__, __loader__, __file__
    import sys, pkg_resources, importlib.util
    __file__ = pkg_resources.resource_filename(__name__, 'test1_parsepointer.so')
    __loader__ = None; del __bootstrap__, __loader__
    spec = importlib.util.spec_from_file_location(__name__,__file__)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
__bootstrap__()

测试脚本

import test1_pptr as tppr

"""
Three functions in tppr should be:
    parse_ptr_v1(int)
    parse_ptr_v2(int)
    parse_val
"""

def main():
    a = int(3)
    print("about to test parse-by-value...")
    tppr.parse_val(a) # runs fine

    print("about to test parse-by-pointer v1...")
    tppr.parse_ptr_v1(a) # runs fine
    
    print("about to test parse-by-pointer v2...")
    tppr.parse_ptr_v2(a) # segfaults

if __name__ == "__main__":
    main()

测试结果

  • parse_val(按值解析,带return NULL分支)运行正常
  • parse_ptr_v1(按指针解析,无return NULL分支)运行正常
  • parse_ptr_v2(按指针解析,带return NULL分支)触发段错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 15:01:13