디스어셈블리 디버깅 도중 어떻게 접근해야 할지 질문 드립니다.
글쓴이: ehaakdl / 작성시간: 금, 2019/10/04 - 6:13오후
ebp2751132 <- esp2750908
생성자 호출 되는시점 문법지점
011ABC50 push ebp 2751132
011ABC51 mov ebp,esp(2750908)
ebp = 2750904 잘못 복사됨 이지점 부터
unordered_map을 추가한 후 부터 클래스 선언만 해도 run time 에러로 스택 손상 떠서
unordered_map이 문제인가 해서 다른 클래스에 넣고 insert/find 해봤습니다. 문제 없이 잘되더군요.--..
그래서 이건 좀 더 깊게 들어가 봐야 알 수 있을거 같아서 디스어셈블리 코드 따라가 봤는데
명령어 mov ebp,esp 에서 기존 esp값이 복사되야 하는데 엉뚱한게 복사 됬습니다. 거기서 부터 잘못된
값이 복사 되서 결국은 _RTC_CheckStackVars 여깃 잡혀서 스택 오염으로 걸렸는데 도대체 왜 잘못된 값이 어디서 유입이 됬길래 그 위로는 아무것도 없는데 ...감이 안잡혀서 질문 드립니다.
class PreferencesMangement
{
public:
PreferencesMangement();
~PreferencesMangement();
bool InitPreferenceVal();
private:
unordered_map<string, void*> mPreferenceVal;
string VerificationNetworkProferty(const char* pProfertyValue, const char* pProfertyName);
};PreferencesMangement::PreferencesMangement()
{
}
PreferencesMangement::~PreferencesMangement()
{
printf("dd");
}
bool PreferencesMangement::InitPreferenceVal()
{
bool bResult = true;
list<string> allFileName;
allFileName.push_back(FILE_NAME_NETWORK);
ifstream openFile;
char readFileLine[MAX_READ_LINE_LENGTH] = { 0 };
char* pSliceRes = nullptr;
char* pAfterSlice = nullptr;
char delemiterProferty = DELIMITING;
char readProfertyName[MAX_PROFERTY_LENGTH] = { 0 };
string errorMsg;
string someFileName;
string someProfertyValue;
list<string>::iterator allFileNameIter;
for (allFileNameIter = allFileName.begin(); allFileNameIter != allFileName.end(); ++allFileNameIter)
{
someFileName.append(PROFERY_FULL_PATH);
someFileName.append(*allFileNameIter);
openFile.open(someFileName, ios::binary);
if (openFile.fail())
{
return false;
}
while (!openFile.eof())
{
openFile.getline(readFileLine, sizeof readFileLine);
if (openFile.fail())
{
allFileName.clear();
openFile.close();
return false;
}
pSliceRes = strtok_s(readFileLine, &delemiterProferty, &pAfterSlice);
if (pSliceRes && pAfterSlice)
{
strcpy_s(readProfertyName, sizeof(readProfertyName),pSliceRes);
someFileName = VerificationNetworkProferty(pAfterSlice, readProfertyName);
if (someFileName.compare(ERROR_MSG[1]))
{
allFileName.clear();
openFile.close();
return false;
}
someProfertyValue.copy(pAfterSlice, sizeof(char)* _MAX_DIR);
//mPreferenceVal.insert(someFileName, someProfertyValue);
}
else
{
allFileName.clear();
openFile.close();
return false;
}
someProfertyValue.clear();
pSliceRes = nullptr;
pAfterSlice = nullptr;
someFileName.clear();
memset(readFileLine, 0, sizeof(readFileLine));
}
allFileName.clear();
openFile.close();
}
return true;
}Forums:


push ebp
push ebp
mov ebp,esp
실행 전에 ebp=2751132, esp=2750908이라면, 위 코드의 실행을 마친 후 ebp에는 2750904가 저장되는 것이 맞습니다.
push ebp가 esp를 4 감소시키기 때문이지요.
위 코드는 x86에서 흔히 보이는 함수 프롤로그인데, 이 정도도 제대로 실행하지 못할 정도로 CPU에 문제가 있다면 아마 부팅도 제대로 안 될 겁니다.
런타임 에러 원인은 어딘가 다른 데 있을 가능성이 높습니다.
container에 스마트 포인터도 아닌 일반 포인터를 쓰는 것은 좋은 습관이 아닙니다.
위의 코드는 mPreferenceVal의 타입을 굳이 unordered_map<string, void*>로 해야 할 이유가 보이지 않는 코드입니다. unordered_map<string, string>으로 선언하면 본문의 문제는 깔끔하게 해결될 겁니다. 해결되는 이유는 차분히 생각해 보시면 알 수 있을 겁니다.
HTML 태그 때문에 이상하게 보여서 다시 씁니다.
텍스트 양식을 plain text 로 하시거나 <
텍스트 양식을 plain text 로 하시거나 <, > 로 작성해 주시면 됩니다. 원글은 제가 텍스트양식을 plain text 로 변경해 드렸습니다.
감사합니다.
감사합니다.
텍스트 양식 선택이 있었군요.
원문 수정해 주셔서 감사합니다.
감사합니다. 충고도 감사 합니다.
아 제가 c++ 배우는중이라 최근에 스마트 포인터 배웠습니다.. 고칠게요
아 그리고 문제는 해결 됬습니다. boost build 다시 하니까 되더라구여..
이상하게 build 했었나 봅니다. boost도 처음 써봐서
그래도 한번 디스어셈블리로 좀 보고 해결해 보고 싶어서 runtime error 잡아보고 싶었는데
unordered_map은 그냥 텍스트로 저장된 환경설정파일 속성값 나중에 더 추가될거 같아서 저장해놓고 두고두고 쓸라고 타입을 저렇게 둔건데 문제가 있나여?
void *로 선언할 경우에는
mPreferenceVal.insert(someFileName, someProfertyValue);에서 someProfertyValue가 지역변수이기 때문에 위의 코드를 갖고 있는 함수가 종료된 시점에서 mPreferenceVal[someFileName이 갖고 있던 문자열]의 포인터 값은 유효한 값이 아니게 됩니다. 나중에 이 값으로 뭔가를 하기 시작하면 이제 지옥이 펼쳐지는 거죠. string으로 선언하면 값이 복사되므로 문제가 없고요. 포인터에 대해 좀 더 공부해 보시기 바랍니다.
감사합니다
insert할때 저는 해당 타입에 맞게 공간이 할당되는줄 알았습니다. 감사합니다.
몇 가지
해당 타입이 뭔가 생각하시면 void*죠? 그러니까 공간 할당은 void*에 대해서 보통 4나 8바이트만 합니다. 그 값을 주소 삼아 찾아가면 나오는 object에 대한 공간은 할당하지 않구요.
그리고 향후 타입이 달라질지도 몰라서 void*를 쓴다고 하셨는데, 그게 STL이 template library인 이유고 템플릿을 쓰는 이유라고 생각합니다. 그게 아니라면 void*가 아니라 inheritance를 사용하는 게 맞다고 여겨집니다.
댓글 달기