首页 > 解决方案 > 带有自定义 Malloc 函数的 CppCheck

问题描述

我正在开发一个包含大量遗留代码的代码库,并且我正在尝试将 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 无法调用Token::addValue()cppcheck/lib/token.cpp

在 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

解决方案


我是一名 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


推荐阅读