如何释放 DLL C++中分配的内存

How to free allocated memory in C++ DLL

本文关键字:C++ 分配 内存 DLL 何释放 释放      更新时间:2023-10-16

我有以下代码来加密C++ DLL 中的字符串

EXPORT WCHAR* EncryptString(WCHAR* stringToEncrypt) {
    aes_context ctx;
    WCHAR* in = stringToEncrypt;
    WCHAR* out;
    WCHAR* key = L"TestKey";
    BYTE* buffEnc = (BYTE*)malloc(16);
    BYTE* keyBuffEnc = (BYTE*)malloc(32);
    memset(buffEnc, 0, 16);
    memset(keyBuffEnc, 0, 32);
    memcpy(buffEnc, in, wcslen(in) * 2);
    memcpy(keyBuffEnc, key, wcslen(key) * 2);
    aes_set_key(&ctx, keyBuffEnc, 256);
    aes_encrypt(&ctx, buffEnc, buffEnc);
    out = (WCHAR*)buffEnc;
    // free(buffEnc);   
    // free(keyBuffEnc);
    return out;
}

我的问题是我无法释放分配的内存,否则结果会损坏。我想知道如何在不丢失结果的情况下释放已用内存?我必须更改返回值的类型吗?

提前感谢您的帮助。问候海因茨

这确实是一个有问题的情况 - 你返回一个指向分配内存的指针,并且不清楚谁应该释放内存。您有以下选项:

  1. 告诉调用方使用 free() 释放内存 - 这只有在他们使用相同的堆时才有效,这很难保证。这是非常不可靠的,并不真正推荐。
  2. 引入内存管理接口(例如freeEncrypted()库中实现的函数(并告诉调用者使用它 - 然后内存将返回到正确的堆。
  3. 使用众所周知的 CoTaskMemAlloc() 进行分配,并告诉调用方使用匹配函数(如 CoTaskMemFree()(来释放内存。这类似于第 2 点,只是使用了一个众所周知的公共内存管理器。
  4. 更改接口,使其接受指向已分配数据的指针及其大小,以便调用方分配和释放内存。

在 Windows 上,内存管理器(除其他外,它跟踪进程中分配的和可用的内存(在 C 运行时库中工作。这意味着,如果你有两个模块(比如:你的实际可执行文件和一个DLL,或两个DLL(,并且你想允许一个模块分配一些内存,另一个应该拥有它(即负责释放它或传递维护者(,基本上有三个选项:

  1. 您让调用方分配一段内存,并将指向该内存的指针传递给被调用方。在您的示例中,这将归结为调用方分配一个(希望足够大的(缓冲区,然后将指向该缓冲区的指针传递给EncryptString函数。这种方法的优点是,调用方可以选择只在堆栈上分配一段内存,然后传递一个指向该内存的指针,类似于

    WCHAR buf[1024];
    EncryptString( "Hello", buf ); // Won't compile, "Hello" is a const string
    

    缺点是调用方必须首先确定适当的缓冲区大小。您可以只施加最大限制并记录它,或者您可以公开一个专用函数来计算所需的大小,或者您可以说如果NULL作为输出缓冲区传递,则该函数返回所需字符数。后者通常由Windows API使用。

  2. 你让被调用方分配内存(就像你的函数现在所做的那样(,例如 mallocnew但随后指示调用者必须使用特殊功能再次释放内存,例如 FreeEncryptedString(char *s) .这个想法是这个释放函数也由你的DLL公开,它只是调用适当的释放函数(即 freedeletedelete[]等(,以便在同一模块内进行分配和解除分配。

  3. 确保两个模块动态链接到同一个 C 运行时库,即进程中只有一个 C 运行时 DLL 副本,并且两个模块都使用它。在这种情况下,您可以根据需要使用mallocfree(或newdelete等(。这样做的优点是它非常简单,缺点是这意味着你对模块的构建方式提出了要求(如果你在一个加载其他人编写的插件的程序上工作,这可能是不可能的 - 这些插件可能会选择静态链接到 C 运行时(。