DLL の境界を越えて CRT オブジェクトを渡す場合に発生する可能性のあるエラー

DLL ((CRT)DLL の境界を越える関数呼び出し)またはからファイル ハンドルロケール環境変数など C のランタイム オブジェクトに渡すと予期しない動作が DLLDLL を呼び出すファイルが CRT ライブラリの複数のコピーを使用して実行できます。

関連の問題はメモリ (明示的に newmalloc かまたは暗黙的に strdupなど) strstreambuf::str 割り当てた後解放する DLL の境界を越えてポインターを渡すときに発生します。DLL とユーザーが CRT ライブラリの複数のコピーを使用する場合にアクセス違反やメモリのヒープが破損する可能性があります。

この問題の別の症状はデバッグ中に出力ウィンドウのエラーなどがあります :

[出力] ヒープ : 指定された RtlValidateHeap への無効なアドレス (#)#

原因

CRT ライブラリの各コピーに異なる個々の状態があります。したがってファイル ハンドルなどの CRT オブジェクト環境変数およびロケールはこれらのオブジェクトを割り当てるか設定の CRT のコピーに対してのみ有効です。DLL とユーザーが CRT ライブラリの複数のコピーを使用するとDLL の境界を越えて CRT これらのオブジェクトを渡しています。反対側に正しく実行されることができません。

またCRT ライブラリの各コピーに 1 個の CRT ライブラリのメモリを割り当て成功独自のヒープ マネージャーがあるためCRT ライブラリのコピーが解放 DLL の境界を越えてポインターはヒープ破損の考えられる原因です。

CRT の境界を越えてオブジェクトを渡すかメモリの割り当てDLL の外部で解放されると予想どおりに DLL をデザインする DLL と CRT ライブラリの同じコピーを使用する DLL のユーザーを制限します。両方の CRT DLL と同じバージョンとリンクしたときのみの DLL とユーザーはCRT ライブラリの同じコピーを使用します。これはVisual C++ 4.1 でビルドされた DLL またはそれ以前のバージョンの Visual C++ 5.0 で作成されたアプリケーションが混在する問題になる可能性があります。Visual C++ 4.1 で使用されている CRT ライブラリの DLL バージョンを msvcrt40.dll でビジュアル 5.0 で使用される 1 種類が msvcrt.dll であるためこれらの DLL に CRT ライブラリの同じコピーを使用するアプリケーションをビルドすることはできません。

ただし例外もあります。Windows 2000 の米国の英語バージョンおよび他のいくつかのローカライズ版ではフランス語とドイツ語チェコ語などmsvcrt40.dll (Version 4.20) フォワーダーのバージョンが提供されます。その結果DLL とリンクが msvcrt40.dll ユーザーが msvcrt.dll とリンクがmsvcrt40.dll へのすべての呼び出しで msvcrt.dll に転送するためCRT ライブラリの同じコピーを使用します。

ただしこの msvcrt40.dll フォワーダーのバージョンが日本語韓国語や中国語などWindows 2000 のローカライズ Edition では使用できません。したがってアプリケーションが対象がこれらのオペレーティング システムまたはが必要な場合はmsvcrt40.dll に依存しない取得します。または CRT ライブラリの同じコピーの使用に依存しないアプリケーションが変更されたりする DLL のアップグレード バージョンを示します。DLL を開発する場合これは Visual C++ 4.2 以降でビルドし直すことを意味します。これはサード パーティの DLL の場合アップグレードの販売元に連絡する必要があります。

次の事項に注意してください。msvcrt40.dll: (Version 4.20) フォワーダーこの DLL のバージョンは再配布できません。

ms235460.collapse_all(ja-jp,VS.110).gifDescription

この例ではDLL の境界を越えてファイル ハンドルを渡します。

DLL や .exe ファイルは /MD で作成されているのでCRT の単一のコピーを共有します。

これらは CRT のコピーを使用するように /MT とビルドすると結果 test1Main.exe を実行するとアクセス違反が発生します。

ms235460.collapse_all(ja-jp,VS.110).gifコード

// test1Dll.cpp
// compile with: /MD /LD
#include <stdio.h>
__declspec(dllexport) void writeFile(FILE *stream)
{
   char   s[] = "this is a string\n";
   fprintf( stream, "%s", s );
   fclose( stream );
}

ms235460.collapse_all(ja-jp,VS.110).gifコード

// test1Main.cpp
// compile with: /MD test1dll.lib
#include <stdio.h>
#include <process.h>
void writeFile(FILE *stream);

int main(void)
{
   FILE  * stream;
   errno_t err = fopen_s( &stream, "fprintf.out", "w" );
   writeFile(stream);
   system( "type fprintf.out" );
}

ms235460.collapse_all(ja-jp,VS.110).gif出力

this is a string

ms235460.collapse_all(ja-jp,VS.110).gifDescription

この例ではDLL の境界を越えて環境変数を渡します。

ms235460.collapse_all(ja-jp,VS.110).gifコード

// test2Dll.cpp
// compile with: /MT /LD
#include <stdio.h>
#include <stdlib.h>

__declspec(dllexport) void readEnv()
{
   char *libvar;
   size_t libvarsize;

   /* Get the value of the MYLIB environment variable. */ 
   _dupenv_s( &libvar, &libvarsize, "MYLIB" );

   if( libvar != NULL )
      printf( "New MYLIB variable is: %s\n", libvar);
   else
      printf( "MYLIB has not been set.\n");
   free( libvar );
}

ms235460.collapse_all(ja-jp,VS.110).gifコード

// test2Main.cpp
// compile with: /MT /link test2dll.lib
#include <stdlib.h>
#include <stdio.h>

void readEnv();

int main( void )
{
   _putenv( "MYLIB=c:\\mylib;c:\\yourlib" );
   readEnv();
}

ms235460.collapse_all(ja-jp,VS.110).gif出力

MYLIB has not been set.

CRT の 1 種類のコピーは使用するための DLL や .exe ファイルと /MD の両方がビルドされプログラムが正常に動作し次の出力が生成されます :

New MYLIB variable is: c:\mylib;c:\yourlib

参照

関連項目

CRT ライブラリの機能