如何解决Coverity检测出的OVERRUN缓冲区溢出问题?
嘿,我来帮你捋清楚这个Coverity报错的问题哈!先看看工具给出的错误提示:
Event overrun-buffer-arg: Overrunning buffer pointed to by "mainAppName" of 17 2-byte elements by passing it to a function which accesses it at element index 259 (byte offset 519) using argument "260ULL".
错误到底啥意思?
简单说,你调用wcsnlen_s的时候,给了第二个参数MAX_PATH(一般是260),但mainAppName指向的字符串字面量L"AIScreenshot.exe"总共才17个宽字符(算上最后的\0终止符)。wcsnlen_s的逻辑是最多检查你传入的第二个参数个数的字符,直到找到终止符,这就意味着它会尝试去读字符串终止符后面的内存(最多读到第260个位置),Coverity就判定这是缓冲区越界风险——虽然这里是字符串字面量,内存后面大概率是安全的,但这种写法确实存在隐患,万一哪天这个指针指向的是一个刚好不够大的缓冲区,就真的会出问题。
怎么修复?
核心就是给wcsnlen_s传对第二个参数:也就是目标字符串所在缓冲区的真实大小。给你两种靠谱的写法:
写法一:把指针改成数组,用_countof获取大小
把字符串定义成数组而不是指针,这样就能用_countof(或者C++17以后的std::size)直接拿到缓冲区的总元素个数:
wchar_t* GetMainAppPath() { const wchar_t mainAppName[] = L"AIScreenshot.exe"; const wchar_t agentName[] = L"AIScreenshotAgent.exe"; size_t lenOfMainApp = wcsnlen_s(mainAppName, _countof(mainAppName)); size_t lenOfAgent = wcsnlen_s(agentName, _countof(agentName)); // 后续逻辑... }
这种写法最安全,_countof会在编译期计算数组的大小,不会出错。
写法二:直接用字符串字面量的长度(适合指针场景)
如果你一定要用指针定义字符串,那可以手动计算缓冲区大小:
wchar_t* GetMainAppPath() { const wchar_t* mainAppName = L"AIScreenshot.exe"; const wchar_t* agentName = L"AIScreenshotAgent.exe"; // 字符串字面量的总大小除以单个宽字符的大小,得到总元素数(含终止符) size_t mainBufSize = sizeof(L"AIScreenshot.exe") / sizeof(wchar_t); size_t agentBufSize = sizeof(L"AIScreenshotAgent.exe") / sizeof(wchar_t); size_t lenOfMainApp = wcsnlen_s(mainAppName, mainBufSize); size_t lenOfAgent = wcsnlen_s(agentName, agentBufSize); // 后续逻辑... }
不过这种写法要注意,字符串字面量必须和变量定义的内容完全一致,不然会出错,所以更推荐第一种数组的写法。
另外,其实因为你的字符串都是以\0结尾的字面量,直接用wcslen(mainAppName)也能拿到正确长度,但wcsnlen_s是更安全的版本(防止遇到没有终止符的字符串),所以还是建议用上面的写法来符合安全规范,同时消除Coverity的报错。
内容的提问来源于stack exchange,提问作者Tom Xue

