gpt4 book ai didi

c++ - C++/ActiveX用malloc,memcpy,free替换了realloc。功能和性能测试

转载 作者:太空狗 更新时间:2023-10-29 20:42:08 25 4
gpt4 key购买 nike

我已被分配到一个项目,该项目是用C++和ActiveX编写的大约10年的复杂遗留系统。

该安装程序是Microsoft Visual Studio 2008。

尽管系统目前没有问题,但作为旧系统安全审查的一部分,由于安全漏洞,自动安全代码扫描工具已将重新分配实例标记为不良实践问题。

这是因为realloc函数可能会将敏感信息的副本留在内存中,无法被覆盖。该工具建议用malloc,memcpy和free代替realloc。

现在,realloc函数具有通用性,它将在源缓冲区为null时分配内存。当缓冲区的大小为0时,它还会释放内存。我能够验证这两种情况。
资料来源:MDSN图书馆2001

realloc returns a void pointer to the reallocated (and possibly moved) memory block. The return value is NULL if the size is zero and the buffer argument is not NULL, or if there is not enough available memory to expand the block to the given size. In the first case, the original block is freed. In the second, the original block is unchanged. The return value points to a storage space that is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.



因此,我使用malloc,memcpy和free的替换函数必须适应这些情况。

我在原始代码段(数组实现)的下方复制了该代码段,该代码段使用realloc动态调整和缩小其内部缓冲区的大小。

首先是类的定义:
template <class ITEM>
class CArray
{
// Data members:
protected:
ITEM *pList;
int iAllocUnit;
int iAlloc;
int iCount;

public:
CArray() : iAllocUnit(30), iAlloc(0), iCount(0), pList(NULL)
{
}

virtual ~CArray()
{
Clear(); //Invokes SetCount(0) which destructs objects and then calls ReAlloc
}

现有的ReAlloc方法:
void ReAllocOld()
{
int iOldAlloc = iAlloc;

// work out new size
if (iCount == 0)
iAlloc = 0;
else
iAlloc = ((int)((float)iCount / (float)iAllocUnit) + 1) * iAllocUnit;

// reallocate
if (iOldAlloc != iAlloc)
{
pList = (ITEM *)realloc(pList, sizeof(ITEM) * iAlloc);
}
}

以下是我的实现,将其替换为malloc,memcpy和free:
void ReAllocNew()
{
int iOldAlloc = iAlloc;

// work out new size
if (iCount == 0)
iAlloc = 0;
else
iAlloc = ((int)((float)iCount / (float)iAllocUnit) + 1) * iAllocUnit;

// reallocate
if (iOldAlloc != iAlloc)
{

size_t iAllocSize = sizeof(ITEM) * iAlloc;

if(iAllocSize == 0)
{
free(pList); /* Free original buffer and return */
}
else
{
ITEM *tempList = (ITEM *) malloc(iAllocSize); /* Allocate temporary buffer */

if (tempList == NULL) /* Memory allocation failed, throw error */
{
free(pList);
ATLTRACE(_T("(CArray: Memory could not allocated. malloc failed.) "));
throw CAtlException(E_OUTOFMEMORY);
}

if(pList == NULL) /* This is the first request to allocate memory to pList */
{
pList = tempList; /* assign newly allocated buffer to pList and return */
}
else
{
size_t iOldAllocSize = sizeof(ITEM) * iOldAlloc; /* Allocation size before this request */
size_t iMemCpySize = min(iOldAllocSize, iAllocSize); /* Allocation size for current request */

if(iMemCpySize > 0)
{
/* MemCpy only upto the smaller of the sizes, since this could be request to shrink or grow */
/* If this is a request to grow, copying iAllocSize will result in an access violation */
/* If this is a request to shrink, copying iOldAllocSize will result in an access violation */
memcpy(tempList, pList, iMemCpySize); /* MemCpy returns tempList as return value, thus can be omitted */
free(pList); /* Free old buffer */
pList = tempList; /* Assign newly allocated buffer and return */
}
}

}
}
}

笔记:
  • 在新旧代码中都可以正确构造和销毁对象。
  • 未检测到内存泄漏(由CRT调试堆函数内置的Visual Studio报告:http://msdn.microsoft.com/en-us/library/e5ewb1h3(v=vs.90).aspx)
  • 我编写了一个小型测试工具(控制台应用程序),该工具可以执行以下操作:

    一种。添加500000个包含2个整数和一个STL字符串的类的实例。

    添加的整数正在运行,其字符串表示形式如下:
    for(int i = 0; i < cItemsToAdd; i++)
    {
    ostringstream str;
    str << "x=" << 1+i << "\ty=" << cItemsToAdd-i << endl;
    TestArray value(1+i, cItemsToAdd-i, str.str());
    array.Append(&value);
    }

    b。打开一个大日志文件,其中包含86526行不同长度的行,并添加到以下数组的实例:CStrings CArray和CArray of string。

  • 我使用现有方法(基准)和修改后的方法来运行测试工具。我在调试和发布版本中都运行了它。

    结果如下:

    测试1:调试版本->添加具有int,int,string,100000实例的类:

    原始实现:5秒,修改实现:12秒

    测试2:调试版本->添加具有int,int,string,500000实例的类:

    原始实现:71秒,修改后的实现:332秒

    测试3:发布版本->添加具有int,int,string,100000实例的类:

    原始实现:2秒,修改实现:7秒

    测试4:发布版本->添加具有int,int,string,500000实例的类:

    原始实现:54秒,修改实现:183秒

    将大日志文件读取到CString对象的CArray中:

    测试5:调试版本->使用86527行读取大日志文件CString of CString

    原始实现:5秒,修改实现:5秒

    测试6:发布版本->使用86527行读取大日志文件CString of CString

    原始实现:5秒,修改实现:5秒

    将大日志文件读取到字符串对象的CArray中:

    测试7:调试版本->使用86527行CArray字符串读取大日志文件

    原始实现:12秒,修改实现:16秒

    测试8:发布版本->使用86527行CArray字符串读取大日志文件

    原始实现:9秒,修改实现:13秒

    问题:
  • 从上述测试中可以看到,与memalloc,memcpy和free相比,realloc始终更快。在某些情况下(例如Test-2),其速度高达367%。同样,对于测试4,它是234%。那么,我该怎么做才能减少这些数字,这与重新分配实现相当?
  • 我的版本可以提高效率吗?

  • 假设:
  • 请注意,我不能使用C++ new和delete。我只需要使用malloc和free。我也不能更改任何其他方法(因为它是现有功能),因此影响巨大。因此,我全力以赴,以尽我所能获得最佳的realloc实现。
  • 我已验证修改后的实现在功能上是正确的。

  • PS:这是我的第一篇SO帖子。我试图尽可能详细。也建议张贴。

    最佳答案

    首先,我想指出的是您没有解决该漏洞,因为免费释放的内存没有像realloc一样被清除。

    还要注意,您的代码比旧的realloc还要多:当内存不足时,它将引发异常。这可能是徒劳的。

    为什么您的代码比重新分配慢?可能是因为realloc正在使用您无法使用的高级快捷方式。例如,realloc分配的内存可能比实际请求的要多,或者在上一个块结束之后分配连续的内存,因此您的代码比realloc进行的内存更多。

    以防万一。在CompileOnline中运行以下代码将得到结果Wow no copy

    #include <iostream>
    #include <stdlib.h>

    using namespace std;

    int main()
    {

    void* p = realloc(NULL, 1024);
    void* t = realloc(p, 2048);

    if (p == t)
    cout << "Wow no copy" << endl;
    else
    cout << "Alas, a copy" << endl;
    return 0;
    }

    您可以采取什么措施来加快代码速度?
    您可以 try to allocate more memory after the currently allocated block,但是由于您需要记住分配的所有指针,或者找到一种方法来修改由free使用的查找表以一次释放正确的内存量,因此释放内存变得更加困难。

    要么

    使用以下通用策略:(内部)分配的内存是先前分配的内存的两倍,并且(可选)仅在新阈值小于分配的内存的一半时才缩小内存。
    这给了您一些余地,因此并不是每次内存增加时都需要调用malloc / memcpy / free。

    关于c++ - C++/ActiveX用malloc,memcpy,free替换了realloc。功能和性能测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19826688/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com