cppcheck overlappingWriteFunction 检查器完全指南:检测 memcpy() 等函数的重叠读写未定义行为

发布时间:2026/10/5 6:37:02
cppcheck overlappingWriteFunction 检查器完全指南:检测 memcpy() 等函数的重叠读写未定义行为 开发工具静态分析代码质量质量保障【免费下载链接】cppcheckstatic analysis of C/C code项目地址https://gitcode.com/gh_mirrors/cpp/cppcheck点击查看免费下载导读本文以 cppcheck 官方检查器文档 man/checkers/overlappingWriteFunction.md 为骨架结合 lib/checkother.cpp、cfg/std.cfg 与 test/testother.cpp 中的源码实现和测试用例系统讲解overlappingWriteFunction检查器它识别对memcpy()等仅允许不重叠数据区操作的函数传入重叠源/目标区间这一未定义行为UB。读完本文你将掌握该检查器的触发条件、底层区间重叠判定算法、库配置library cfg如何声明不允许重叠的函数集合以及如何用memmove()修复此类缺陷。检查器概览属性值消息MessageOverlapping read/write in memcpy() is undefined behavior分类CategoryUndefined Behaviour未定义行为严重级别SeverityError适用语言LanguageC/C检查器 IDoverlappingWriteFunctionoverlappingWriteFunction是 cppcheck 默认启用的 error 级检查器之一由CheckOther检查类负责实现。它对应的缺陷模式是调用memcpy()这类函数时源区间与目标区间发生重叠——而只有memmove()家族函数被标准允许处理重叠区间memcpy()等函数在区间重叠时属于未定义行为。缺陷的本质为什么 memcpy 不允许重叠memcpy()区别于memmove()的实现可以自由选择对平台最快的拷贝顺序——正向、反向或分块拷贝——其前提假设是源与目标从不重叠。一旦二者重叠拷贝过程可能覆盖掉尚未读取的源数据导致结果被破坏而且这种破坏在不同编译器、不同优化级别、不同标准库实现之间表现各异。因此文档给出的核心指导是只有当 cppcheck 能确定被拷贝的精确大小时它才报告此问题它不会仅仅因为两个区间看起来可疑地接近但大小无法确定就发出警告。这条精确性优先的设计原则在源码中有直接体现下文会展开说明。触发条件与官方示例官方Before示例触发检查#include cstring void foo() { char a[10]; memcpy(a, a1, 2u); // - source and destination overlap }这里a1与a指向同一数组a[10]内的相邻字节拷贝 2 字节时源区间[1, 3)与目标区间[0, 2)重叠属于未定义行为。官方After修复示例#include cstring void foo() { char a[10]; memmove(a, a1, 2u); // memmove() is defined to handle overlap safely }memmove()被标准明确要求以如同先拷贝到临时缓冲区再拷贝回来的方式处理重叠因此是安全的。源码实现原理checkOverlappingWrite 的工作流该检查器由 lib/checkother.cpp 中CheckOtherImpl::checkOverlappingWrite()见 lib/checkother.cpp#L4762-L4858实现在 CheckOther::runChecks 中被调度执行。整个流程可拆解为三个阶段阶段一识别不允许重叠数据的函数检查器遍历每个函数作用域functionScopes内的全部 token当遇到形如%name% (的函数调用时通过mSettings.library.getNonOverlappingData(tok)lib/library.cpp#L1630-L1635查询库配置判断该函数是否声明了not-overlapping-data属性const Library::NonOverlappingData *nonOverlappingData mSettings.library.getNonOverlappingData(tok); if (!nonOverlappingData) continue;NonOverlappingData结构体lib/library.h#L151-L157记录五个参数位置struct NonOverlappingData { int ptr1Arg; // 第一个指针目标所在参数位置 int ptr2Arg; // 第二个指针源所在参数位置 int sizeArg; // 大小参数位置-1 表示无大小参数 int strlenArg; // strlen 类参数位置当前实现中有 TODO未使用 int countArg; // 元素个数参数位置 };这些属性来自库配置文件中的not-overlapping-data元素解析代码见 lib/library.cpp#L886-L892nonOverlappingData.ptr1Arg functionnode-IntAttribute(ptr1-arg, -1); nonOverlappingData.ptr2Arg functionnode-IntAttribute(ptr2-arg, -1); nonOverlappingData.sizeArg functionnode-IntAttribute(size-arg, -1); nonOverlappingData.strlenArg functionnode-IntAttribute(strlen-arg, -1); nonOverlappingData.countArg functionnode-IntAttribute(count-arg, -1);阶段二确定被拷贝的精确大小这是精确性优先原则的落点。以memcpy在 cfg/std.cfg 中的声明为例cfg/std.cfg#L3990-L4010function namememcpy,std::memcpy not-overlapping-data ptr1-arg1 ptr2-arg2 size-arg3/ ... /function而wmemcpy则使用count-arg声明元素个数cfg/std.cfg#L4011-L4031function namewmemcpy,std::wmemcpy not-overlapping-data ptr1-arg1 ptr2-arg2 count-arg3/ ... /function源码中大小参数取sizeArg与countArg的较大者const int sizeArg std::max(nonOverlappingData-sizeArg, nonOverlappingData-countArg); if (sizeArg 0 || sizeArg args.size()) { // 没有大小参数sizeArg -1时的特例处理见阶段三 ... } // 大小参数必须具有已知整数值否则放弃检查 if (!args[sizeArg-1]-hasKnownIntValue()) continue; MathLib::bigint sizeValue args[sizeArg-1]-getKnownIntValue();关键点若大小参数不是编译期可确定的常量检查器直接跳过。这正是文档所述不会仅因两个区间可疑接近就警告的代码依据。若使用count-arg元素个数语义还需乘以元素大小换算成字节数。阶段三解析指针偏移并判定区间是否重叠两个指针参数经由getBufAndOffset()lib/checkother.cpp#L4704-L4760解析为基指针 字节偏移它支持三种表达式形态a[i]形式提取数组基地址与下标按下标元素大小换算字节偏移指针算术a i/i a形式根据 valueType 判断哪一侧是指针计算元素大小与偏移纯指针表达式无偏移偏移记为 0若带大小参数则同时把大小乘以元素尺寸如2u * sizeof(a[0])这类表达式。得到offset1、offset2与sizeValue后执行区间不重叠判定if (offset1 offset2 offset1 sizeValue offset2) continue; // 区间 1 完全在区间 2 之前不重叠 if (offset2 offset1 offset2 sizeValue offset1) continue; // 区间 2 完全在区间 1 之前不重叠 // 否则两个区间存在重叠注意这是闭区间判定两个区间只要首尾相接不相交如memcpy(a[0], a[4], 4u)[0,4)与[4,8)就不报告——相邻但不重叠是安全的。最后还需确认两个基指针在语义上是同一表达式isSameExpression否则也不报告确认重叠后调用overlappingWriteFunction(tok, tok-str())lib/checkother.cpp#L4865-L4868上报void CheckOtherImpl::overlappingWriteFunction(const Token *tok, const std::string funcname) { reportError(tok, Severity::error, overlappingWriteFunction, Overlapping read/write in funcname () is undefined behavior); }消息文本中的函数名取自实际调用的函数如memcpy、wmemcpy、strcpy因此输出具有针对性。无大小参数函数的特例同一表达式直接报告对于sizeArg -1的函数例如strcpy(ptr, ptr)这种没有长度参数的调用源码走特例分支lib/checkother.cpp#L4821-L4829只要两个指针是完全相同的表达式就直接报告重叠——因为完全相同意味着重叠必然发生if (nonOverlappingData-sizeArg -1) { if (!isSameExpression(macro, ptr1, ptr2, mSettings, pure, follow, errorPath)) continue; overlappingWriteFunction(tok, tok-str()); }测试用例验证行为边界一览test/testother.cpp 的checkOverlappingWrite()测试test/testother.cpp#L13878-L13969完整验证了上述判定逻辑是理解边界条件的黄金材料测试代码期望结果说明memcpy(a[5], a[4], 2u)报告a[i]下标形式重叠memcpy(a5, a4, 2u)报告指针算术形式重叠memcpy(a, a1, 2u)报告与官方文档示例一致memcpy(a[0], a[4], 4u)不报告[0,4)与[4,8)首尾相接不重叠memcpy(a[5], a[4], 2u * sizeof(a[0]))报告大小含sizeof乘法#10350memcpy(K[0], K[1], sizeof(K[0]))不报告相邻元素各拷 1 个不重叠#12638memcpy(K[0], K[1], 2 * sizeof(K[0]))报告拷 2 个元素必然重叠wmemcpy(a[5], a[4], 2u)报告count-arg语义生效strcpy(ptr, ptr)报告sizeArg -1同一表达式特例这些用例表明检查器对恰好相邻不重叠的拷贝保持克制避免误报只有区间真正相交时才报错。关联检查器与规则映射overlappingWriteFunction与 overlappingWriteUnion 是同源缺陷重叠读写的两种表现前者是函数调用传入重叠区间后者是同一表达式内对 union 两个重叠成员读写如u.i u.f;。二者共享相同的消息风格与 error 级别。在规则映射层面MISRA C 规则 19.1 被映射到这两个检查器见 lib/checkersidmapping.cpp#L144 与 addons/misra.py#L1387MISRA 0-2-1 也覆盖这两个 IDlib/checkersidmapping.cpp#L30。也就是说在--misra-*相关配置下运行 addon 时重叠读写问题会被同时计入 MISRA 合规检查。实战建议优先改用memmove()凡源/目标可能来自同一缓冲区数组移位、就地平移、重叠区拷贝直接用memmove()消除 UB无需分析具体偏移。注意恰好相邻是安全的memcpy(a[0], a[4], 4u)这类拷贝不会触发检查因为区间不重叠但边界条件一旦随代码演进如大小变为2 * sizeof立即会被报告。大小必须可静态确定如果拷贝大小来自运行时变量本检查器不会告警遵循精确性优先此时应人工审视或借助其他手段确认区间关系。库函数可扩展not-overlapping-data是 library cfg 的通用机制参考 cfg/std.cfg 中memcpy、wmemcpy的写法自定义库函数若也要求不重叠可按ptr1-arg/ptr2-arg/size-arg/count-arg语法在 cfg 中声明使检查器自动覆盖。参考路径官方检查器文档man/checkers/overlappingWriteFunction.md关联检查器文档man/checkers/overlappingWriteUnion.md检查器实现lib/checkother.cpp、声明见 lib/checkother.h#L266库配置解析lib/library.cpp#L886-L892、lib/library.h#L151-L158函数声明示例cfg/std.cfg#L3990-L4031测试用例test/testother.cpp#L13878-L13969MISRA 规则映射lib/checkersidmapping.cpp#L144、addons/misra.py#L1387赞分享开发工具静态分析代码质量质量保障【免费下载链接】cppcheckstatic analysis of C/C code项目地址https://gitcode.com/gh_mirrors/cpp/cppcheck点击查看免费下载相关推荐cppcheck overlappingWriteUnion 检查器详解捕获联合体同一表达式中的重叠读写未定义行为cppcheck overlappingWriteUnion 检查器详解捕获联合体同一表达式中的重叠读写未定义行为 本指南围绕 cppcheck 静态分析器的开发工具静态分析代码质量质量保障cppcheck floatConversionOverflow 检查器详解浮点转整数的未定义行为检测cppcheck floatConversionOverflow 检查器详解浮点转整数的未定义行为检测 导读 本文深入讲解 cppcheck 的 floatC开发工具静态分析代码质量质量保障Cppcheck autoVariables 检查器深度解析局部变量地址经函数参数泄漏的未定义行为检测Cppcheck autoVariables 检查器深度解析局部变量地址经函数参数泄漏的未定义行为检测 本文围绕 Cppcheck 的 autoVariabl开发工具静态分析代码质量质量保障上一篇OwlCarousel2 代码风格检查JSHint配置与常见错误修复下一篇LunaTranslator 语音识别Speech Recognition功能实战指南Windows 语音识别两种模式详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考