2009-09-30 3 views
1

DllImport를 사용하여 자체 .net 클래스에서 C 랩퍼 라이브러리의 메소드를 호출합니다. 이 메서드는 C DLL을 문자열 변수를 만들고 문자열 포인터를 반환합니다.여유 메모리가 메모리 블록을 지우지 않음

이와 비슷한 것;

_declspec(dllexport) int ReturnString() 
{ 
char* retval = (char *) malloc(125); 
strcat(retval, "SOMETEXT"); 
strcat(retval, "SOMETEXT MORE"); 
return (int)retval; 
} 

그럼 난 Marshall.PtrToStringAnsi (PTR)를 사용하여 문자열을 읽었다. 문자열의 복사본을 얻은 후에는 free (ptr)를 호출하는 C 래퍼 라이브러리에있는 다른 c 메서드 HeapDestroy를 호출합니다.

여기에 질문이 있습니다. 최근에는 매력처럼 작동하면서 "보호 된 메모리 영역을 읽거나 쓰려고했습니다."라는 예외가 생기기 시작했습니다. 더 깊은 분석 후, 나는이 포인터에 대해 무료 메서드를 호출했지만 포인터의 값이 지워지지 않고 무의식적으로 힙을 채우고이 예외를 throw하도록 iis 작업자 프로세스를 만듭니다. 그건 그렇고, 그것은 C 라이브러리 에서이 방법을 호출 웹 사이트 프로젝트입니다.

이 문제에 대해 저에게 친절히 도와 주시겠습니까?

물론 여기 C# 코드가 있습니다.

[DllImport("MyCWrapper.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] 
    private extern static int ReturnString(); 

    [DllImport("MyCWrapper.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] 
    private extern static void HeapDestroy(int ptr); 

    public static string GetString() 
    { 
     try 
     { 

      int i = ReturnString(); 
      string result = String.Empty; 
      if (i > 0) 
      { 
       IntPtr ptr = new IntPtr(i); 
       result = Marshal.PtrToStringAnsi(ptr); 
       HeapDestroy(i); 
      } 

      return result; 
     } 
     catch (Exception e) 
     { 
      return String.Empty; 
     } 
    } 
+0

사용중인 C# 코드를 게시 하시겠습니까? –

+0

C# 코드를 추가했습니다. 감사합니다 –

답변

7

근본적인 C 코드가 문제 일 수 있습니다. strcat가 의존하는 문자열에 NULL 종결자를 추가하지 않습니다 (또는 malloc에서 NULL 반환을 확인). 이 시나리오에서 손상된 메모리를 얻는 것은 쉽습니다. 다음을 수행하여 문제를 해결할 수 있습니다.

retval[0] = '\0'; 
strcat(retval, "SOMETEXT"); 

또한이 문제의 일부는 시스템에서 트릭을하고 있다는 것입니다. 올바르게 작성하고 시스템이 올바르게 작동하는 코드로 작업하게하는 것이 훨씬 좋습니다. 첫 번째 단계는 문자열을 제대로 반환하도록 원시 코드를 수정하는 것입니다. 한 가지 고려해야 할 것은 특정 유형의 메모리 만 CLR (HGlobal 및 CoTask 할당)을 통해 기본적으로 해제 할 수 있다는 점입니다. 따라서 char*을 반환하고 다른 할당자를 사용하도록 함수 서명을 변경할 수 있습니다.

_declspec(dllexport) char* ReturnString() 
{ 
char* retval = (char *) CoTaskMemAlloc(125); 
retval[0] = '\0'; 
strcat(retval, "SOMETEXT"); 
strcat(retval, "SOMETEXT MORE"); 
return retval; 
} 

다음 C# 서명을 사용하고 Marshal.FreeCoTaskMem을 사용하여 IntPtr을 해제 할 수 있습니다.

[DllImport("SomeDll.dll")] 
public static extern IntPtr ReturnString(); 

마샬링 할 때 CLR이 메모리를 확보해야한다고 생각하면 FreeCoTaskMem을 사용하여 메모리를 확보해야합니다. 일반적으로 문자열 반환과 관련이 있습니다. 당신이 CoTaskMemAlloc으로 메모리를 할당하기 때문에 다음 해제 단계를 + 자신에게 마샬링을 저장하고 수행 할 수

[DllImport("SomeDll.dll", CharSet=Ansi)] 
public static extern String ReturnString(); 
+0

나는 그것을 시도 할 것이다! 합리적인 것 같습니다. –

+0

JaredPar, 당신의 대답은 매우 도움이됩니다. 그러나 ansi-c에서 CoTaskMemAlloc과 같은 점에 대한 또 다른 질문은 표준 라이브러리에있는 것입니까? –

+1

@Emrah, 표준 ansi-c 라이브러리에는 해당 항목이 없습니다. ansi-c로 제한된다면 무료 PInvoke 레이어를 작성하고 거기서 IntPtr을 전달해야 할 것입니다. – JaredPar

1

그래서 다시 사용할 수있는 메모리를 해제하는 것은 명확하지 않습니다, 단지 그것을 해제합니다. 당신은 쉽게 같은 0xBAADFOOD로 값 문제를 찾을 수 있도록하는 일부 디버그 메모리를 통해 기록 할 빌드

발신자가 결코 메모리를 할당하지 다시 할당 된 메모리를 통과해야합니다

_declspec(dllexport) int ReturnString(char*buffer, int bufferSize) 
{ 
    if (bufferSize < 125) { 
     return 125; 
    } else { 
     strcat(buffer, "SOMETEXT"); 
     strcat(buffer, "SOMETEXT MORE"); 
     return 0; 
    } 
} 
0

메모리가에 의해 할당되어 있지만 DLL을 응용 프로그램과 동일한 힙에 있으면 링크 된 라이브러리에 따라 다른 메모리 관리자를 사용할 수 있습니다. 동일한 정확한 라이브러리를 사용하고 있는지 확인하거나 DLL 코드에서 DLL이 할당하는 메모리를 해제하는 코드를 추가해야합니다.

+0

그렇습니다. 간단한 무료 (ptr) 메서드가 포함 된 HeapDestroy 메서드가 추가 된 이유는 무엇입니까? –

+0

차가움. 나는 당신의 질문을 잘못 읽었습니다. DLL 주위에 래퍼를 작성 했으므로 래퍼 코드가 비어있는 동안 DLL이 alloc을 수행하고 있다고 생각했습니다. – justinhj

+0

제한된 문자열에서 작동하는 안전한 연산을 사용하는 것이 좋습니다. 당신의 버퍼 사이즈를 상수에 넣고, 할당 된 문자열 데이터에 대해 작동하는 함수에 전달하십시오. strncat 등을 사용하십시오. – justinhj

관련 문제