CentOS7下clang14编译带Sanitizer的Python3.9.13源码失败问题
问题根因
- 构建阶段触发Unicode断言、报
character U+6f002f is not in range错误:CentOS 7默认搭载2.17版本glibc,Python 3.9.13默认开启的C locale强制转换逻辑在该版本glibc下读取宽字符时会读到未初始化的栈脏数据;开启ASAN后栈内存不会默认填充0,就会解析出超出Unicode合法范围的非法值触发断言。仅手动设置UTF-8环境变量没有禁用该强制转换逻辑,只是降低了触发概率,未解决根本问题。 - 运行时UBSAN报
applying zero offset to null pointer:属于Python 3.9.13的已知代码缺陷,C标准明确规定空指针参与指针运算(即使偏移量为0)属于未定义行为,原代码未做空指针前置判断就直接执行指针偏移计算,会被UBSAN拦截。 - 构建阶段LeakSanitizer报内存泄漏:是Python解释器初始化阶段分配的全局常驻内存,程序正常退出时不会主动释放,不属于真实内存泄漏,为LSAN误报。
修复步骤
按以下流程操作可完整保留ASAN、UBSAN、pydebug编译选项完成构建,同时解决运行时报错:
- 先安装并生成UTF-8 locale,避免系统locale资源缺失:
yum install -y glibc-langpack-en glibc-locale-source localedef -c -f UTF-8 -i en_US en_US.UTF-8 - 调整configure参数,增加
--without-c-locale-coerce选项禁用C locale强制转换逻辑,从根源避免非法宽字符读取问题,最终配置命令如下:./configure --disable-ipv6 --with-address-sanitizer --with-undefined-behavior-sanitizer --with-pydebug --prefix=/foo/bar --without-c-locale-coerce - 修复
Objects/call.c的空指针运算UB问题:打开文件定位到400行报错位置,在执行指针偏移计算前增加空指针判断,如果目标指针为NULL直接走错误返回分支,不要执行指针运算操作。 - 构建前设置环境变量,绕过LSAN对初始化阶段常驻内存的误报,避免构建流程被打断:
export LC_ALL=en_US.UTF-8 export LANG=en_US.UTF-8 export LANGUAGE=en_US.UTF-8 export ASAN_OPTIONS=detect_leaks=0:allocator_may_return_null=1 export UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=0 - 执行
make -j$(nproc)、make install即可完成构建。
补充说明
- 不要直接注释
Objects/unicodeobject.c里的断言,该断言是非法Unicode值的最后一道拦截,直接注释会导致非法值流入后续逻辑触发更难排查的崩溃;按上述步骤禁用locale强制转换后,该断言不会被触发。 - 如果后续需要用构建好的解释器做内存泄漏检测,不需要一直关闭
detect_leaks,编写LSAN抑制规则文件,将初始化阶段的常驻分配点加入抑制列表即可。 - 构建完成后运行解释器如果还存在其他非致命UBSAN告警,都是Python 3.9.13版本本身的已知小缺陷,不影响核心Sanitizer检测功能的使用,可按需给对应代码加判空逻辑修复。
内容的提问来源于stack exchange,提问作者user14717
相关产品推荐
相关产品推荐

