
CPython 低内存崩溃修复代码编译、解释器通道与_winapi.CreateProcess中的MemoryError规范化【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython本文基于 CPython 主线仓库中的 Misc/NEWS.d/next/Core_and_Builtins/2026-06-09-10-28-30.gh-issue-151126.DKa6Sl.rst 修复记录剖析当设备内存耗尽时代码编译、_interpchannels模块与_winapi.CreateProcess三处可能引发崩溃的路径以及它们如何改为抛出规范的MemoryError。读完本文你将理解 CPython 在内存分配失败场景下的错误处理约定、各修复点的底层代码位置以及如何在低内存环境下验证该行为。修复背景内存耗尽时的崩溃风险在嵌入式设备、容器或长期运行的守护进程中内存可能在任何时刻被耗尽。CPython 内部大量使用malloc/calloc及自有内存分配器当分配失败时C 层代码必须检查返回值并转入 Python 错误处理流程。然而历史上部分路径在分配失败时未做检查或直接返回NULL而未设置异常导致解释器在上层拿到NULL时触发段错误segfault而非可捕获的MemoryError。本次修复issue gh-issue-151126针对三类场景代码编译阶段Python/compile.c的编译器对象分配解释器通道模块_interpchannelsModules/_interpchannelsmodule.c中的锁与等待项分配Windows 专属的_winapi.CreateProcessModules/_winapi.c内部缓冲分配。修复的统一手段是在分配失败处调用PyErr_NoMemory()其内部通过_PyErr_NoMemory(tstate)设置MemoryError确保NULL返回值始终伴随异常从而让上层以异常而非崩溃的方式失败。代码编译编译器对象与作用域单元的分配检查代码编译由 Python/compile.c 实现。该文件在两处分配失败路径上补充了PyErr_NoMemory()new_compiler()约 Python/compile.c#L171-L185使用PyMem_Calloc(1, sizeof(compiler))分配编译器上下文若返回NULL立即调用PyErr_NoMemory()并返回NULL。此前若未设置异常调用方会把NULL当作一般错误处理在无异常状态下继续解引用进而可能崩溃。_PyCompile_EnterScope()约 Python/compile.c#L599-L609进入新的作用域单元struct compiler_unit时同样使用PyMem_Calloc分配失败时调用PyErr_NoMemory()并返回ERROR标志。该函数为每个函数、类或模块作用域创建编译单元是编译多层嵌套代码时的热路径内存耗尽时极易在此触发问题。此外Python/codegen.c 与 Python/assemble.c 等编译链路的其他文件中也已普遍存在PyErr_NoMemory()检查例如Python/assemble.c#L421、Python/codegen.c#L141-L162说明编译器整体遵循“分配失败即设异常”的约定本次修复补全了剩余缺口。解释器通道_interpchannels的锁与等待项分配_interpchannels是 CPython 子解释器subinterpreter之间进行通道channel通信的内部模块实现在 Modules/_interpchannelsmodule.c。该模块中大量使用PyThread_allocate_lock()分配线程锁并在等待队列中管理_waiting_t结构这些分配在极端内存压力下同样可能失败。本次修复在该文件的 9 处分配失败点统一补上了PyErr_NoMemory()分布在 Modules/_interpchannelsmodule.c#L466、#L604、#L683、#L862、#L921、#L1115、#L1314、#L1700、#L1743 等位置。以等待项初始化为例Modules/_interpchannelsmodule.c#L461-L475static int _waiting_init(_waiting_t *waiting) { PyThread_type_lock mutex PyThread_allocate_lock(); if (mutex NULL) { PyErr_NoMemory(); /* 分配失败设置 MemoryError 而不是静默返回 NULL */ return -1; } *waiting (_waiting_t){ .mutex mutex, .status WAITING_NO_STATUS, }; return 0; }从源码结构看_interpchannels中还有更多PyThread_allocate_lock()、动态数组扩容等分配点文件共 3661 行PyErr_NoMemory()出现 9 处本次 NEWS 条目描述的即是这批低内存路径的系统性加固目标是让通道接收recv、发送send与等待waiting操作在内存不足时以MemoryError优雅失败。_winapi.CreateProcessWindows 进程创建前的缓冲分配_winapi是 CPython 在 Windows 上的进程创建内部模块Modules/_winapi.c其CreateProcess包装了 Win32 APICreateProcessW。该函数在真正调用系统 API 之前需要完成多项内存分配getenvironment()将环境变量映射转换为宽字符wchar_t*环境块PyUnicode_AsWideCharString()将命令行字符串转为可写的宽字符副本属性列表lpAttributeList等结构的内存管理。当这些分配在低内存下失败时路径直接goto cleanup若失败发生在未设置异常的分配上上层就会在无异常状态下继续最终崩溃。本次修复在这些分配失败点补上了PyErr_NoMemory()例如 Modules/_winapi.c#L1078、#L1134、#L1195、#L1280、#L1685、#L2027、#L2409使得CreateProcess在内存耗尽时抛出可捕获的MemoryError而不是让进程创建代码崩溃。需要说明的是CreateProcessW系统调用本身失败例如可执行文件不存在、权限不足时代码走的是另一条路径调用PyErr_SetFromWindowsErr(GetLastError())抛出对应 Windows 错误Modules/_winapi.c#L1422-L1425。本次修复只涉及调用系统 API 之前的内部内存分配失败两者错误语义互不干扰。修复的统一模式与验证方式三处修复遵循同一模式内存分配 API 返回NULL→ 调用PyErr_NoMemory()→ 返回NULL/错误码。PyErr_NoMemory()是 CPython 中设置MemoryError的标准入口其底层为_PyErr_NoMemory(tstate)见 Python/bltinmodule.c#L1588 的引用用法确保异常与NULL返回值严格配对。这一约定在 CPython 内存错误处理中具有普适性整个代码库Python/compile.c、Python/codegen.c、Python/assemble.c、Python/ceval.c、Python/crossinterp.c、Python/codecs.c等均大量使用PyErr_NoMemory()。由于修复点位于解释器内部普通用户难以直接构造内存耗尽场景但可以通过以下方式验证相关行为单元测试运行_winapi相关测试验证CreateProcess的异常路径测试位于 Lib/test/test_winapi.py注入式测试在支持 fault injection如LD_PRELOAD拦截malloc返回NULL的环境中运行 Python可观察代码编译compile()内建函数与子解释器通道操作在低内存下抛出MemoryError而非段错误受限内存运行使用ulimit -vLinux等工具限制虚拟内存后执行嵌套函数编译或_interpchannels通信验证异常可被try/except MemoryError捕获。修复意义小结本次修复消除了三类低内存崩溃路径将“设备内存耗尽”从解释器段错误转变为标准 Python 异常修复点所在文件失败场景代码编译Python/compile.c编译器对象、作用域单元分配失败解释器通道Modules/_interpchannelsmodule.c线程锁、等待项等分配失败进程创建Modules/_winapi.cCreateProcess内部缓冲分配失败对应用开发者而言这意味着在内存受限的部署环境中compile()、子解释器通道通信以及 Windows 进程创建代码可以依赖try/except MemoryError进行优雅降级与资源回收而不是面对无法捕获的进程崩溃对 CPython 内核开发者而言这是一次低内存健壮性OOM-resilience的常规加固与此前代码库中既有的PyErr_NoMemory()约定保持一致。【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考