디스어셈블리 디버깅 도중 어떻게 접근해야 할지 질문 드립니다.
글쓴이: 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를 사용하는 게 맞다고 여겨집니다.
댓글 달기