带有自定义 Malloc 函数的 CppCheck
Posted
技术标签:
【中文标题】带有自定义 Malloc 函数的 CppCheck【英文标题】:CppCheck with custom Malloc functions 【发布时间】:2020-12-10 18:17:56 【问题描述】:我正在开发一个包含大量遗留代码的代码库,我正在尝试将 CppCheck 更新到最新版本。
此代码依赖于许多具有以下签名的自定义 malloc
样式函数:
Status osMemAlloc(void** ptr, size_t numBytes);
此函数的签名意味着 CppCheck 没有推断出函数 osMemAlloc
正在为 ptr
分配内存,这意味着它在代码中标记了 nullPointer 空指针取消引用错误,例如:
SomeStruct* myPtr = NULL;
Status status = osMemAlloc((void**)& myPtr, sizeof(SomeStruct));
A
assert(status == SUCCESS_E);
pT
myPtr->param1 = val1; // (error) nullPointer Null pointer dereference
myPtr-> param2 = val2; // (error) nullPointer Null pointer dereference
我如何告诉 CppCheck 对 osMemAlloc((void**)& myPtr, sizeof(SomeStruct))
的调用正在为 myPtr
分配内存。
将函数的签名更改为更自然的东西不是一种选择,因为代码库非常庞大且非常脆弱,没有适当的测试工具。
更多信息
我尝试使用各种宏定义(手动扩展)替换osMemAlloc()
的调用作为解决此问题的一种方法,并相信 CppCHeck 中存在一个错误,其中强制转换导致 CppCheck 错过分配给指针的内存分配.
分配的原始调用站点具有以下形式:
if (osMemAlloc((void **)&device,sizeof(DeviceInfo)) == OS_OK)
CPPCheck 很高兴将 osMemAlloc 替换为一个宏,该宏将扩展为:
if ((((*(&device)=cppcheck_HeapAlloc(sizeof(Device))) != NULL)
? SUCCESS_E : ERROR_E) == SUCCESS_E)
不幸的是,GCC 对该调用不满意,因为它需要强制转换为 (void**) 以匹配原始函数。如果添加了该演员,则代码变为:
if ((((*((void**)(&device))=cppcheck_HeapAlloc(sizeof(Device))) != NULL)
? OS_OK : OS_ERROR) == OS_OK)
这会导致 CPPCheck 失败。我相信演员阵容足以导致CppCheck无法在cppcheck/lib/token.cpp中调用Token::addValue()
在 CppCheck 中失败的完整示例代码:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
typedef struct Device
uint32_t param1;
uint32_t param2;
Device;
enum Status
OS_OK = 0,
OS_ERROR = 1
;
// Macro used to hide/replace OS Abstraction of Malloc in legacy code.
// The real code forwards to a function withe following signature:
// Status osMemAlloc(void** ptr, size_t sx);
#define osMemAlloc(ptr, sz) ((*(ptr)=malloc(sz)) != NULL ? OS_OK : OS_ERROR)
int main()
Device* device1 = NULL;
Device* device2 = NULL;
/// This call / expansion of the macro without the casts is fine,
if ((((*(&device1)=malloc(sizeof(Device))) != NULL) ? OS_OK : OS_ERROR) == OS_OK)
device1->param1 = 10;
device1->param2 = 20;
/// Note the cast is ncessary when the real function is called for C++
//if ((((*((void**)&device2)=malloc(sizeof(Device))) != NULL) ? OS_OK : OS_ERROR) == OS_OK)
if (osMemAlloc((void**)&device2, sizeof(Device)) == OS_OK)
device2->param1 = 10; // error: Null pointer dereference: device2 [nullPointer]
device2->param2 = 20; // error: Null pointer dereference: device2 [nullPointer]
printf("Done\n");
free(device1);
free(device2);
The Output from CppCheck
cppcheck.exe cppcheck-error.c
Checking cppcheck-error.c ...
cppcheck-error.c:39:7: error: Null pointer dereference: device2 [nullPointer]
device2->param1 = 10; // error: Null pointer dereference: device2 [nullPointer]
^
cppcheck-error.c:26:22: note: Assignment 'device2=NULL', assigned value is 0
Device* device2 = NULL;
^
cppcheck-error.c:39:7: note: Null pointer dereference
device2->param1 = 10; // error: Null pointer dereference: device2 [nullPointer]
^
cppcheck-error.c:40:7: error: Null pointer dereference: device2 [nullPointer]
device2->param2 = 20; // error: Null pointer dereference: device2 [nullPointer]
^
cppcheck-error.c:26:22: note: Assignment 'device2=NULL', assigned value is 0
Device* device2 = NULL;
^
cppcheck-error.c:40:7: note: Null pointer dereference
device2->param2 = 20; // error: Null pointer dereference: device2 [nullPointer]
^
【问题讨论】:
【参考方案1】:我是一名 Cppcheck 开发人员。
我不知道内置配置选项或可能的解决方法。不知道该推荐什么。
一种技巧是将代码复制到某个临时文件并创建一个脚本 (sed/python/..) 来重写您的代码:
Status status = osMemAlloc((void**)& myPtr, sizeof(SomeStruct));
进入:
Status status = success; myPtr = malloc(sizeof(SomeStruct));
更合适的解决方案是在 Cppcheck 中添加改进。如果您有兴趣提供修复,请随时查看。在我看来,代码并不是超级复杂,没有必需的依赖项,所以如果你有一个可以编译 hello world 程序的 C++ 编译器,你也应该能够编译 Cppcheck。源码:https://github.com/danmar/cppcheck
【讨论】:
感谢您的回复 - 我相信 CPpCheck 中存在与强制转换为 (void**) 的错误。我在上面添加了更多信息。 抱歉,一开始我误解了你的意思。我已经创建了这张票:trac.cppcheck.net/ticket/10047希望你认为这看起来不错。它应该很快修复..但如果你想要一个快速的解决方案,请随时查看它。 :-) 编辑:如果你解决了,请提供一个 github pull request。以上是关于带有自定义 Malloc 函数的 CppCheck的主要内容,如果未能解决你的问题,请参考以下文章
cppcheck警告:变量未在带有初始化初始化的构造函数中实例化