정리

across DLL boundaries (cross-DLL problem)

저장소/VC++

출처 MSDN: https://msdn.microsoft.com/ko-kr/library/ms235460.aspx


실수는 돌고 돌고 반복되고...


static link library로 바꾸거나 run-time library를 md로 변경하거나.

shared_ptr 을 삭제자를 지정해서 사용하면 극복 mt runtime에서 극복 가능??





DLL 경계를 넘어 CRT 개체를 전달할 때 발생할 수 있는 오류

Visual Studio 2015

파일 핸들, 로케일, 환경변수 같은 C Run-time(CRT) 객체를 DLL의 내부 혹은 외부로 전달할 때 ( DLL의 경계를 지나는 함수 호출), DLL 이나 DLL을 호출한 파일에서 서로 다른 CRT 라이브러리 사본을 사용하고 있다면, 예기치 않은 문제가 발생할 수 있습니다.

메모리를 할당하고 (명시적인 new와 malloc이나 암시적으로 strdup, strstreabuf::str 등 ) 할당된 메모리의 포인터를 DLL의 경계를 넘어서 전달한 뒤 이를 해제하게 되면 문제가 발생할 수 있습니다. DLL과 이를 사용하는 쪽에서 CRT 라이브러리의 서로 다른 사본을 사용한다면 메모리 액세스 위반이나 힙 손상이 발생할 수 있습니다.

이 문제의 또 다른 현상으로 디버깅 중 출력창에 다음과 같은 오류가 나타날 수 있습니다.

HEAP[]: 잘못된 주소를 RtlValidateHeap(#,#)로 지정합니다.

CRT라이브러리의 각 복사본은 분리되어 다른 상태에 있습니다. 따라서, 파일 핸들, 환경 변수와 로캘같은 CRT 객체들은 이들 객체들이 할당되어있거나 설정되어있는 CRT의 복사본에 대해서만 유효합니다. DLL과 사용자가 CRT 라이브러리의 여러 복사본을 사용할때, DLL 경계를 넘어 이러한 CRT개체들을 전달할 수 있고 반대편에서 올바르게 선택되기 위해 이들을 제외합니다.

또한, CRT 라이브러리의 각 복사본이 자신의 힙 관리자를 가지기때문에, 하나의 CRT 라이브러리에서 메모리를 할당하는 것과 CRT라이브러리의 다른 복사본으로 해제되기 위한 DLL 경게를 통해 포인터를 전달하는 것은 힙 손상을 잠재적인 원인이 됩니다.

만일 경계를 통해 CRT개체들을 전달하거나 메모리를 할당하거나, DLL외부를 해제하기 위해 DLL을 디자인하는 경우, DLL로 CRT라이브러리의 동일한 복사본을 사용하기 위한 DLL 사용자를 제한합니다. DLL과 이것의 사용자는 둘다 CRT DLL의 같은 버전을 사용하여 연결된 경우에만 CRT라이브러리의 동일한 복사본을 사용합니다. 만일 Visual C++ 4.1또는 그 이전버전으로 빌드된 DLL을 사용하여 Visual C++ 5.0과 함께 혼합된 응용프로그램을 빌드할 경우 이런 문제가 생길 수 있습니다. Visual C++ 4.1에 의해 사용되는 CRT라이브러리의 DLL버전이 msvcrt40.dll이고 Visual 5.0을 사용하는경우 msvcrt.dll을 사용하기 때문에, 이들 DLL들로 CRT라이브러리의 동일한 복사본을 사용하기 위해 응용프로그램을 빌드할 수 없습니다.

그러나 여기에는 예외가 있습니다. 영어 (미국)과 독일어, 프랑스어, 체코어와 같은, Windows 2000의 일부 다른 지역화된 버전에서 msvcrt40.dll(버전 4.20)이 전달됩니다. 결과적으로, msvcrt40.dll을 사용하여 연결된 DLL과 msvcrt.dll을 사용하여 연결된 이것의 사용자들을 통해, 모든 호출이 msvcrt.dll로 전달되어진 msvcrt40.dll에 의해 만들어지기 때문에 CRT라이브러리의 동일한 복사본을 사용할 수 있습니다.

그러나, msvcrt40.dll의 이 전달자 버전은 일본어, 한국어, 중국어와 같은, Windows 2000의 몇몇 지역화된 버전들에서 사용될 수 없습니다. 만일 응용프로그램이 이러한 운영체제를 대상으로 하는 경우, CRT라이브러리의 동일한 복사본을 사용을 필요로 하지 않는 응용프로그램을 고치거나 msvcrt40.dll을 필요로하지 않는 DLL의 업그레이드된 버전을 얻는 것 중에 하나를 필요로 합니다. 만일 DLL을 개발한다면, 이것은 Visual C++ 4.2 또는 그 이후를 사용하여 다시 빌드해야하는 것을 의미합니다. 만일 이것이 제 3자의 DLL이면, 업그레이드에 대한 공급업체에 문의해야 합니다.

이 msvcrt40.dll(버전 4.20)의 전달자 DLL버전은 재배포될수 없음에 주의하세요.

ms235460.collapse_all(ko-kr,VS.140).gif설명

이 예제는 DLL경계를 통해 파일 핸들을 전달합니다.

DLL과 .exe 파일은 /MD를 사용하여 빌드되어서 그들이 CRT의 단일 복사본을 공유합니다.

만일 CRT의 분리된 복사본을 사용하도록 /MT를 사용하여 리빌드된 경우, test1Main.exe 결과를 실행하는 것은 접근 위반에서 실행합니다.

ms235460.collapse_all(ko-kr,VS.140).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(ko-kr,VS.140).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(ko-kr,VS.140).gifOutput

this is a string

ms235460.collapse_all(ko-kr,VS.140).gif설명

이 예제에서는 DLL 경계를 통해 환경 변수를 전달합니다.

ms235460.collapse_all(ko-kr,VS.140).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(ko-kr,VS.140).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(ko-kr,VS.140).gifOutput

MYLIB has not been set.

만일 CRT의 복사본을 하나만 사용하도록 /MD과 함께 DLL 및.exe 파일이 빌드되는 경우, 프로그램이 성공적으로 실행하고 다음과 같이 출력됩니다:

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


'저장소 > VC++' 카테고리의 다른 글

ATL and MFC String Conversion Macros 사용 시 주의할 점  (0) 2016.04.08
VS2012의 tuple  (0) 2014.09.17
[펌] shlwapi 의 파일 경로 관련 API 모음  (0) 2014.08.13
strftime format 좀 기억하자!  (0) 2014.08.08
SQLite - Syntax  (0) 2014.05.27