[C/C++] DLL 함수 호출 후 변수가 초기화 되는 오류 (memset)

윤찬호·2023년 1월 26일
0

에러

목록 보기
4/6

2~3일 동안 고생한 문제... 😕

현상

A프로젝트의 funcA 함수에서는 B.dll의 funcB 함수를 호출한다.

int funcA(unsigned char* cpData, int nDataLen, int nNum)
{
    funcB(pContext);
}

문제는 funcB 함수가 호출된 이후 funcA 함수의 파라미터 였던 cpData, nDtaLen, nNum 변수들이 전부 NULL 또는 0으로 초기화 되는 것이다. (funcB 에서는 cpData, nDataLen, nNum 변수를 매개변수로 받지 않는다.)


B.dll의 funcB 함수를 호출하는 방식에도 2가지 방식이 있었는데,

첫 번째 방식으로 호출했을 때는 cpData가 가리키고 있던 메모리에는 데이터가 그대로 있었지만, 해당 데이터를 가리키는 주소를 잃어버렸다. (직접 호출이 아닌 다리를 거쳐서 호출)

두 번째 방식으로 호출했을 때는 cpData가 가리키고 있던 메모리 자체가 0x00으로 초기화 되었고. (직접적으로 호출)

(원래 소스는 첫 번째 방식으로 호출하는 것이다, 두 번째 방식은 테스트로 시도한 방식이다)

해결과정

초기화 되는 변수들(funcA의 매개변수로 받은 변수들)을 funcA 함수 안에서 새로운 변수들로 복사 하는것이였다. 매개변수로 받았던 변수들은 전부 초기화 되었지만 복사해둔 변수들은 정상적으로 남아 있었고 이후 코드 실행에 문제는 없었다. 하지만 문제를 해결했다고 볼 순 없다.


A와 B가 하나의 프로젝트 였으면 디버깅 하면서 찾기 쉬웠겠지만, 그렇지 않기 때문에 문제를 찾는게 매우 어려웠다. (어느 시점에 A의 메모리가 날라가는지 알 수 없다.)

결국 funcB 함수의 한 줄, 한 줄을 주석 처리하면서 빌드하고. A프로젝트에서 디버깅 하면서 문제의 코드를 찾기 시작했다.

funcB 함수는 절대 적은 양의 소스 코드가 아니다.. B프로젝트 자체가 매우 큰 프로젝트 이고, 이 함수 안에서 다른 여러 함수들을 호출하기 때문에 정만 맨 땅에 헤딩할 생각으로 시작했다.

결론

정말 다행히도 문제가 되는 코드는 금방 찾았다.

memset(pContext, 0x00, sizeof(CONTEXT); // CONTEXT는 구조체

메모리 관련 문제이니 memset 부분에 문제가 있지 않을까 생각은 들었지만, 크게 기대는 하지 않았었다.

funcA의 cpData, nDtaLen, nNum 변수들이 funcB의 매개변수로 들어가는 것도 아니고, 아무런 연관이 없어 보이는데 영향이 있을까 싶었다. ← 이 생각 때문에 원인을 찾는게 더 어려웠다


위에 문제가 되는 memset 코드는 문법적으로 잘못된 것은 아니다.

다만 funcB에서 sizeof(CONTEXT)를 했을 때의 값과, funcA에서 sizeof(CONTEXT)를 했을 때의 값이 달랐다. (funcB에서의 sizeof 값이 더 컸다.)

즉, 같은 구조체인데 크기가 다른 것이다.

확인해보니 A프로젝트에서 import한 헤더 파일에 정의되어 있는 CONTEXT 구조체에는 변수 2개가 빠져 있었다.


결국 pContext를 초기화(memset)하는데 실제 초기화 작업을 하는 B프로젝트 입장에서는 (A에서 원했던 영역보다) 훨씬 큰 범위를 0x00으로 초기화를 해서 (운이 나쁘게?) A프로젝트의 cpData, nDataLen, nNum 변수들이 초기화 된 것 같다. (메모리상 바로 옆에 붙어 있어서 초기화 되지 않았을까 싶다.)

PS

지금도 의문이 드는 것은 '#현상' 에서 첫 번째 방식으로 호출 했을 때의 결과이다.

첫 번째 방식으로 호출 했을 때는 왜 메모리가 0x00으로 초기화 되지 않았을까? funcB 호출 이후 변수는 값을 잃었지만 메모리에는 여전히 데이터가 남아 있었다.

DLL 호출 방식에서 어떤 차이가 있어서 그러지 않을까 싶은데 그 부분에 대해서는 더 알아봐야 겠다.

0개의 댓글