2009-11-13 5 views
0

C# 응용 프로그램에서 관리되지 않는 Dll을 호출 할 때 AccessViolationException이 표시됩니다. 이상한 점은 내 보낸 함수에 인수가 없으므로 데이터 마샬링에 문제가 없다는 것입니다. 이 함수는 인수를 얻지 않고 그냥 정수를 반환합니다. 또한 호출 규칙은 문제가되지 않습니다. 동일한 제로 인수와 정수 반환 값 (그러나 다른 이름)을 가진 동일한 함수는 정상적으로 작동합니다. 마샬링 및 소집 규칙이 배제되었다는 사실을 고려할 때 그러한 호출이이 예외를 유발할 수있는 남은 후보 사유는 무엇인가?비 관리 dll 호출시 액세스 위반

업데이트 : 일반 링크를 통해 다른 관리되지 않는 코드에서 호출 된 경우 dll 함수가 정확하므로 완벽하게 작동합니다.

업데이트 2 : 모든 것이 컴파일되어 32 비트에서 실행됩니다. 나는 승 XP SP2와 비스타를 시도했다. 흥미로운 사실은 다음과 같습니다. Vista 시스템에서는 매력처럼 작동합니다. XP에서는 실패합니다.

업데이트 3 : 나는 소스 코드를 얻지 못했지만 본질적으로이 DLL이 무엇인지 배웠다. 그래서 나는 내 자신의 dll로 문제를 재현하려고 시도했다. 이 이야기는 다음과 같습니다. 원본 dll은 el.lib (Erlang의 c 인터페이스 라이브러리)에 대한 래퍼입니다. 일부 도우미 기능을 내 보냅니다. 그래서 문제를 재현하기 위해 하나의 함수, 즉 "test()"만 내보내는 ei.lib 주위에 래퍼 DLL을 만들었습니다. 나는 마샬링과 물건으로 엉망이되지 않도록 그렇게했다. 나는 초기화를 테스트하고, 메시지를 보내고 연결하기를 원했다. 그래서 내 DLL의이 test() func는 ei_connect_init()을 호출하고, 그 다음에 ei_connect() 및 finaly ei_reg_send()을 호출하며, 내부에 하드 코딩 된 인수가 있습니다. 문제는 내가이 DLL을 호출하고 다른 비 관리 코드에서 test() 함수를 사용하면 문제가 없다는 것입니다. 메시지가 전송되었습니다. 하지만 C#에서 DllImport를 호출하면 Vista에서만 작동합니다. XP가 아닙니다. XP에서는 .net 레이어의 AccessViolationException으로 실패합니다. 나는 문제를 추적하려고했는데 내 dll 안의 호출에서 ei_connect()에 대한 호출 또는 erl_errno (이것들은 ei.lib에 정의되어 있음)을 읽으려는 것을 볼 수 있습니다. XP에서 실행 중이고 관리되는 코드에 의해 호출되면 보호 된 메모리를 읽거나 쓰면 앱이 다운됩니다. Vista에서는 작동하기 때문에 사소한 일은 없으며 비 관리 코드에 의해 호출 될 때 작동합니다.

답변

1

나는 문제를 알고 있다고 생각한다 : ei.lib는 TLS (Thread Local Storage)를 사용한다.

#ifdef __WIN32__ 
#ifdef USE_DECLSPEC_THREAD 
/* Define (and initialize) the variable __erl_errno */ 
volatile __declspec(thread) int __erl_errno = 0; 
#else 
static volatile DWORD errno_tls_index = TLS_OUT_OF_INDEXES; 
static LONG volatile tls_init_mutex = 0; 
#endif 
#endif 

USE_DECLSPEC_THREAD 경우가 정의되지 않은 소스 파일에서 낮은, TLS API를 대신 사용하는 경우 : EI 인터페이스 소스 코드의 파일 ei_pthreads.c에서이 조각이있다.

윈도우 운영 체제에서

윈도우 비스타 전에, __declspec(thread) 몇 가지 제한 사항이 있습니다 지금, MSDN에서 난 것을 발견했다. DLL 이 로컬이 아닌 데이터 또는 개체 을 __declspec(thread)으로 선언하면 동적으로 이로드되면 에 보호 오류가 발생할 수 있습니다. DLL에 LoadLibrary가로드 된 후 코드가 로컬이 아닌 __declspec(thread) 데이터를 참조 할 때마다 시스템 오류가 발생합니다. 스레드가 실행시 할당 의 전역 변수 공간이이 공간의 크기가 응용 프로그램의 요구 사항을 더한 연결 정적이다 모든 DLL을의 요구 사항 계산을 기반으로하기 때문에. LoadLibrary를 사용할 때 을 __declspec(thread)으로 선언 한 스레드 로컬 변수를 허용하도록이 공간을 확장 할 수 없습니다. DLL에 TLS API (예 : TlsAlloc)를 사용하여 DLL에 LoadLibrary가로드 된 이있는 경우 TLS를 할당합니다. 나는 창에 대한 얼랑의 미리 컴파일 된 바이너리 배포판과 함께 제공되는 ERL 인터페이스 libs와 사용하기 때문에

그래서, 나는 그 바이너리를 컴파일 할 때 그들이 USE_DECLSPEC_THREAD를 정의하는 경우 궁금합니다. 그렇지 않다면 나는 막 다른 길을 가고 있으며 다른 일을하려고 할 것입니다. 그들이 그것을 정의했다면 나는 cygwin을 설치하고 그것을 정의하지 않고 소스를 재 컴파일해야한다. (Yikes ...).

최종 업데이트 : 실제로 이것은 문제였습니다. cygwin을 설치하고 USE_DECLSPEC_TRHEAD을 정의하지 않고 erl_interface 코드를 다시 컴파일해야했습니다. 또한 재 컴파일 할 때 작은 변경이 필요하므로 _WIN32_WINNT이 정의되어있는 경우에만 USE_DECLSPEC_THREAD의 누락 뒤에 코드에서 winbase.h에 정의 된 SwitchToThread를 사용하기 때문에 _WIN32_WINNT의 정의가 winbase.h를 포함하기 전에 발생합니다. 0x400보다 큰 값

0

이 예외는 관리되지 않는 코드로 인해 메모리 액세스 위반이 발생할 때 발생합니다. 관리되지 않는 기능이 올바른지 확인하십시오. 비 관리 코드의 소스가있는 경우 enable 디버거가 비 관리 코드에 들어가서 문제가있는 곳을 확인할 수도 있습니다.

+0

아니요, 이것은 문제가되지 않습니다 ... 내 업데이트보기 : ( – Paralife

+0

또한 소스 코드에 액세스 할 수 없으므로 적어도 디버그 정보가있는 객체를 얻고 디버거에 샷을 시도합니다. – Paralife

+0

관리되지 않는 라이브러리에 사용하기 전에 호출해야하는 일종의 정적 초기화 함수가 있습니까? 32 <-> 64 비트가 일치하지 않는지 확인하십시오. 관리되지 않는 코드가 32 비트이고 관리가 64로 실행되는 경우이 예외가 발생할 수도 있습니다 –