【发布时间】: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]
^
【问题讨论】:
标签: cppcheck