ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

cppcheck argumentSize 检查器:函数定长数组参数与实参尺寸不匹配的静态分析实战

cppcheck argumentSize 检查器:函数定长数组参数与实参尺寸不匹配的静态分析实战 开发工具静态分析代码质量质量保障【免费下载链接】cppcheckstatic analysis of C/C code项目地址https://gitcode.com/gh_mirrors/cpp/cppcheck点击查看免费下载导读本文围绕 cppcheckC/C 静态分析工具内置的argumentSize检查器展开讲解它如何检测函数声明为定长数组参数如void f(char a[10])却被调用方传入更小数组这一典型缓冲区隐患。阅读本文后你将掌握该检查器的触发条件、告警消息格式与多行错误路径error path解读、底层实现原理源码级、与 CWE/安全标准MISRA、AUTOSAR、CERT的映射关系以及如何在自己的项目中运行、验证与规避该告警。检查器总览argumentSize是 cppcheck 缓冲区越界检查族CheckBufferOverrun中的一个告警类检查器其元数据定义于 man/checkers/argumentSize.mdMessage告警消息Buffer a is too small, the function f expects a bigger buffer in 1st argumentCategory分类Correctness正确性Severity严重级别Warning警告Language适用语言C/C在 cppcheck 的检查器注册表lib/checkers.cpp中该检查器对应实现CheckBufferOverrun::argumentSize默认严重级别为warning与同族的arrayIndex、bufferOverflow等检查器并列同属于 lib/checkbufferoverrun.cpp 中实现的缓冲区安全分析体系。检查器触发条件与典型代码形态核心触发模式当一个函数以定长数组形式声明参数例如void f(char a[10])而调用处传入一个尺寸已知且更小的数组时cppcheck 即报告argumentSize告警void f(char a[10]); void g() { char a[2]; f(a); // - a 只有 2 个元素小于 f() 期望的 10 个元素 }在 C 语言中数组作为函数参数时会退化为指针void f(char a[10])与void f(char *a)在 ABI 层面并无差别但声明中的[10]构成了对调用方的一份文档化契约函数内部按至少 10 个元素来使用该缓冲区。cppcheck 正是利用这一声明契约与实际传入数组的已知尺寸做比较。多维数组同样适用该检查并不局限于一维数组多维数组参数的每一个维度都会被逐一比较测试用例见 test/testbufferoverrun.cppvoid f(float a[10][3]); void g() { float a[2][3]; // 第一维 2 10触发告警 f(a); }不同元素类型的定长数组参数同样会被检测char、int、float等均有对应测试见 test/testbufferoverrun.cpp。告警输出格式与错误路径解读argumentSize告警采用 cppcheck 的多行报告multiline格式输出除主告警外还附带完整的错误路径error path用于展示调用点 → 函数参数声明 → 实参声明的完整证据链。以官方测试用例test/testbufferoverrun.cpp为例[test.cpp:4:5]: warning: Buffer a is too small, the function f expects a bigger buffer in 1st argument [argumentSize] [test.cpp:4:5]: note: Function f is called [test.cpp:1:13]: note: Declaration of 1st function argument. [test.cpp:3:10]: note: Passing buffer a to function that is declared here [test.cpp:4:5]: note: Buffer a is too small, the function f expects a bigger buffer in 1st argument其中各行 note 的含义分别为note 内容含义Function f is called标记函数调用发生的位置调用点Declaration of 1st function argument.定位到函数f第一个参数的声明处即void f(char a[10])中的a[10]Passing buffer a to function that is declared here指出传入的实参变量a的声明位置末行重复主告警消息作为错误路径的终点注意消息中的序数词1st、2nd、3rd等源码在 lib/checkbufferoverrun.cpp 通过getOrdinalText定义于 lib/utils.h根据参数索引paramIndex 1生成因此告警消息会明确指出不匹配的是第几个参数。底层实现原理源码级剖析主检查逻辑argumentSize()该检查的实现位于 lib/checkbufferoverrun.cpp核心流程如下启用条件判断仅当warning严重级别被启用或argumentSize被显式启用为 premium 检查时继续第 882-883 行——后文会说明这与 premium 版本的关系。遍历函数作用域从符号数据库SymbolDatabase即 cppcheck 的符号解析结果取出所有函数作用域遍历其中的每个函数调用 token第 887-891 行。逐个参数比较对每个调用取出实参列表与目标函数的形参列表若形参是数组argument-isArray()且双方都有值类型valueType且元素类型一致argument-valueType()-type callargs[paramIndex]-valueType()-type则继续第 896-903 行。剥离成员访问/命名空间前缀通过while (Token::Match(calldata, ::|.)) calldata calldata-astOperand2();处理obj.a、ns::a这类实参表达式最终定位到真正的数组变量第 904-908 行。维度逐项比较要求实参变量与形参的维度数量相同然后对每一维比较已知尺寸——只要实参某一维的已知元素数dim1.num小于形参声明的元素数dim2.num即判定为错误第 909-919 行。报告告警调用argumentSizeError()生成带错误路径的多行告警第 920-921 行。值得注意的实现细节维度比较要求双方dimensions的known标志为真第 915 行即只有尺寸在编译期已知的数组才会被比较。若形参是int a[]未定长或实参尺寸无法静态确定检查不会触发——对应测试用例void f(int a[])不产生告警test/testbufferoverrun.cpp。告警生成argumentSizeError()该函数lib/checkbufferoverrun.cpp负责构建错误路径并上报依次压入三个关键定位点调用点、形参声明处Declaration of N-th function argument.、实参变量声明处Passing buffer x to function that is declared here最终通过reportError上报严重级别Severity::warning检查器 ID 为argumentSize确定性为Certainty::normal即不是 inconclusive 猜测并关联CWE-398Indicator of Poor Code Quality代码质量不良的指示器见 lib/checkbufferoverrun.cpp。在整个缓冲区检查框架中的位置argumentSize由CheckBufferOverrunImpl::check()统一调度lib/checkbufferoverrun.cpp与arrayIndexThenCheck、stringNotZeroTerminated、objectIndex、negativeArraySize等检查器在每次扫描中依次执行。其声明位于 lib/checkbufferoverrun.h。为什么这是一个值得关注的问题C/C 中数组参数声明char a[10]向调用方传达传入缓冲区至少 10 个元素的隐含契约但语言本身并不会阻止调用方传入更小的数组——形参退化为指针后函数内部无从得知真实尺寸。若函数体确实访问了接近声明上限的元素它有权这样做就会越界读写真实更小的数组构成未定义行为undefined behaviour而若函数实际上只触及前几个元素则该次调用碰巧无害。cppcheck 的argumentSize检查只做声明尺寸与实参尺寸的静态比较并不追踪函数体内是否实际访问了靠后的元素后者属于arrayIndexOutOfBounds等索引越界检查的职责。因此该告警是一种强信号无论函数体当前是否越界尺寸契约已被破坏风险真实存在它适合作为契约一致性检查长期运行防止代码演进过程中缓冲区尺寸悄然缩水。相关但更强的检查是 ctuArrayIndex它是 cppcheck 的跨翻译单元whole-program / CTU分析会沿函数调用链追踪缓冲区在普通指针参数如void f(char *p)场景下的越界访问能覆盖argumentSize不追踪的函数体内实际越界情形。两者互补argumentSize关注传小了的契约违约ctuArrayIndex关注用超了的实际越界。如何修复修复前有缺陷void f(char a[10]); void g() { char a[2]; f(a); // - a 小于 f() 期望的尺寸 }修复后正确void f(char a[10]); void g() { char a[10]; f(a); }修复的本质是让调用方的缓冲区尺寸满足或超过函数参数的声明尺寸。实际操作中还可能采取以下策略扩大实参缓冲区如上例使声明契约与实参一致修正形参声明若调用方确实只能提供小缓冲区应将形参改为未定长数组void f(int a[])或指针void f(char *p)并同步传入实际尺寸如void f(char *p, size_t n)消除契约歧义统一接口当同一个函数被多个尺寸不同的缓冲区调用时优先采用指针 长度的显式接口避免依赖数组声明的隐式契约。在项目中的运行与验证方式命令行运行argumentSize属于默认启用的warning级别检查因此只需在项目根目录对源码运行 cppcheck 即可触发cppcheck --enablewarning your_file.c # 或按多行错误路径输出 cppcheck --enablewarning --error-exitcode1 your_file.c若想精确定位该检查器可使用--enable系列选项结合--checkers-report查看每个检查器的启用状态argumentSize在检查器注册表中对应的实现名为CheckBufferOverrun::argumentSizelib/checkers.cpp。测试验证仓库内置的回归测试位于 test/testbufferoverrun.cpp测试函数buffer_overrun_function_array_argument覆盖了以下场景一维char a[10]/char a[2]不匹配 → 告警多维float a[10][3]/float a[2][3]→ 告警int a[20]/int a[2]→ 告警未定长形参int a[]→不告警避免误报通过new分配、尺寸恰好匹配的缓冲区 →不告警test/testbufferoverrun.cpp。规避误报的设计模式为避免在合理代码上误报实践中应避免用小数组实参去调用定长数组形参的写法若不得已可考虑将形参声明为未定长a[]或指针并显式传长度使用 cppcheck 的抑制suppression机制针对特定行/文件放行如需抑制可通过--suppressargumentSize:path/to/file或内联注释实现。与安全编码标准的映射argumentSize已被 cppcheck 的规则映射机制关联到多项安全编码标准映射表维护于 lib/checkersidmapping.cpp并在 lib/checkersreport.cpp 中由CheckBufferOverrun::argumentSize兜底报告标准规则/编号说明MISRA C:2012规则 17.5The function argument corresponding to a parameter declared to have an array type shall not be an array that is smaller than that parameter对应 C 标准库调用场景映射见 lib/checkersidmapping.cpp 与 addons/misra.pyAUTOSAR规则 A5-2-5数组越界族检查的成员之一见 lib/checkersidmapping.cppCERT CARR30-CDo not form or use out-of-bounds pointers or array subscripts见 lib/checkersidmapping.cppMISRA C:2023 等—argumentSize同样被纳入 misrac2012/misrac2023/misrac2025 及 AUTOSAR、CERT C/C 的检查器集合见 lib/settings.cpp这意味着在使用 cppcheck 的--misra、AUTOSAR、CERT 相关报告模式时argumentSize告警会以对应规则号如 MISRA 17.5的形式呈现方便在合规审计流程中追踪。小结argumentSize是 cppcheck 缓冲区安全分析中成本极低、信号明确的一类检查它只需静态比较形参声明尺寸与实参已知尺寸即可在编译阶段发现被 C 语言数组退化机制掩盖的契约违约。结合多维数组支持、多行错误路径与标准映射它非常适合作为长期开启的防御性检查。对于更深层的函数体内实际越界问题可配合 ctuArrayIndex 跨翻译单元分析形成完整防护。进一步阅读检查器实现 lib/checkbufferoverrun.cpp、头文件 lib/checkbufferoverrun.h、回归测试 test/testbufferoverrun.cpp。赞分享开发工具静态分析代码质量质量保障【免费下载链接】cppcheckstatic analysis of C/C code项目地址https://gitcode.com/gh_mirrors/cpp/cppcheck点击查看免费下载相关推荐9 大网盘直链下载工具 LinkSwift在浏览器里免费解析真实下载地址的完整教程9 大网盘直链下载工具 LinkSwift在浏览器里免费解析真实下载地址的完整教程 LinkSwift 是一个基于 JavaScript 的网盘直链下载助手开发工具静态分析代码质量质量保障PHPStan 错误指南arguments.count——函数与方法参数数量不匹配的静态检测与修复PHPStan 错误指南arguments.count——函数与方法参数数量不匹配的静态检测与修复 导读 arguments.count 是 PHPStan开发工具代码质量静态分析ty 类型检查器规则解析invalid-argument-type 如何检测不匹配的函数调用参数ty 类型检查器规则解析 invalid argument type 如何检测不匹配的函数调用参数 在 Ruff 仓库的 ty 类型检查器位于 crates开发工具Lint格式化静态分析CLI上一篇10分钟开启WeakAuras自动更新游戏界面自定义的智能管家下一篇QQ空间记忆保险箱3步永久保存你的青春回忆终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表