3

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;
}

私の問題は、結果が壊れているため、割り当てられたメモリを解放できないことです。結果を失うことなく、使用済みメモリを解放するにはどうすればよいでしょうか。戻り値の型を変更する必要がありますか?

よろしくお願いします。ハインツに挨拶

4

2 に答える 2

8

これは確かに問題のある状況です。割り当てられたメモリへのポインタを返し、誰がメモリを解放すべきかが不明です。次のオプションがあります。

  1. 呼び出し元に使用してメモリを解放するように伝えfree()ます。これは、保証が難しい同じヒープを使用する場合にのみ機能します。これは非常に信頼性が低く、あまりお勧めできません。
  2. メモリ管理インターフェイス (freeEncrypted()ライブラリに実装されている関数など) を導入し、呼び出し元にそれを使用するように伝えます。その後、メモリは適切なヒープに返されます。
  3. 割り当てなどのよく知られたものを使用し、呼び出し元にメモリの解放CoTaskMemAlloc()などの一致する関数を使用するように指示します。CoTaskMemFree()これはポイント 2 に似ていますが、よく知られている一般的なメモリ マネージャーを使用するだけです。
  4. すでに割り当てられているデータへのポインターとそのサイズを受け入れるようにインターフェイスを変更して、呼び出し元がメモリの割り当てと解放の両方を行うようにします。
于 2013-10-02T07:07:20.943 に答える
6

Windows では、メモリ マネージャー (特に、プロセスで割り当てられたメモリと空きメモリを追跡します) は C ランタイム ライブラリで動作します。これは、2 つのモジュール (たとえば、実際の実行可能ファイルと DLL、または 2 つの DLL) があり、1 つのモジュールにメモリを割り当てさせ、もう 1 つのモジュールがそれを所有できるようにする場合 (つまり、メモリを解放するか、基本的に 3 つのオプションがあります。

  1. 呼び出し元にメモリの一部を割り当てさせ、それへのポインターを呼び出し先に渡します。あなたの例では、それは呼び出し元が(できれば十分に大きい)バッファを割り当て、それへのポインタをEncryptString関数に渡すことに要約されます。このアプローチの利点は、呼び出し元がスタックにメモリの一部を割り当ててから、それにポインターを渡すことを選択できることです。

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

    欠点は、呼び出し元が最初に適切なバッファー サイズを把握しなければならないことです。最大制限を課してそれを文書化するか、必要なサイズを計算する専用関数を公開するかNULL、出力バッファーとして渡された場合、関数が必要な文字数を返すと言うことができます。後者は、Windows API で一般的に使用されます。

  2. malloceg orを使用して(関数が現在行っているように)呼び出し先にメモリを割り当てさせますnewが、呼び出し元が特別な関数を使用してメモリを再度解放する必要があることを指示しますFreeEncryptedString(char *s)。アイデアは、この割り当て解除関数も DLL によって公開され、適切な割り当て解除関数 (つまり、またはなど) を呼び出すだけでfreedelete割り当てdelete[]と割り当て解除の両方が同じモジュール内で発生するというものです。

  3. 両方のモジュールが同じ C ランタイム ライブラリに対して動的にリンクしていることを確認します。つまり、プロセス内に C ランタイム DLL のコピーが 1 つだけあり、両方のモジュールがそれを使用します。その場合、必要に応じてmallocand free(またはnewanddeleteなど) を使用できます。これの利点は、非常に単純であることです。欠点は、モジュールの構築方法に要件を課すことを意味することです (他の人が作成したプラグインをロードするプログラムで作業している場合、これは不可能かもしれません。それらのプラグインは、 C ランタイムに対して静的にリンクすることを選択しました)。

于 2013-10-02T07:05:38.423 に答える