문자열 복사, 붙이기 등의 내부 구현이 궁금합니다.
글쓴이: vi08 / 작성시간: 수, 2014/05/14 - 5:07오후
char str1[3] = {0,};
char* str2 = "World";
char* str3 = new char[3];
memset(str3, 0, sizeof(char)* 3);
strcpy(str1, str2);
strcpy(str3, str1);
cout << str1 << ", " << str3 << endl;
getchar();
delete[] str3;
표준 문자열 함수를 재정의해 보던 중, 묘한 걸 발견했습니다. 바로 위와 같은 짧은 코드 때문이었는데요.
strcpy로 str1과 str3 모두 str2의 "World" 문자열이 복사됨은 물론 출력까지 되더군요. 의외의 결과에 당황하고 말았습니다.
물론 오류 메시지는 떴습니다. str1과 str2의 복사에 대한 오류 메시지 역시 짐작이 가고요. 하지만 str3을 delete하려고 했을 때 오류가 뜨는 건 무슨 영문인지 모르겠네요.
해서 뜯어보자! 했더니 어셈블리 코드가 떡하고 저를 반기더군요. 읽을 수 없었습니다ㅋㅋㅋㅠㅠ
메모리 처리가 어떻게 이뤄졌길래 실제 변수의 메모리가 부족함에도 불구하고 복사가 되는 건지 궁금합니다.
아참. 당연히 첫번째 strcpy 역시 제대로 된 복사는 아니었습니다만 변수 이름은 World를 제대로 가리키고 있었습니다. 캡쳐 첨부합니다.
File attachments:
첨부 | 파일 크기 |
---|---|
Cap 2014-05-14 17-03-47-813.png | 15.21 KB |
Forums:
그냥 undefined behaviour입니다. 천번
그냥 undefined behaviour입니다. 천번 실행해서 천번다 똑같아도 우연입니다.
undefined behaviour라고 해서 뭔가 문제를 일으켜야 한다는게 아니라 말그대로 어떻게 동작할지 정의하지 않는 다는 것일 뿐이니까 당연히 정상 작동도 포함됩니다.
극단적인 농담을 하자면, 순간적으로 CPU를 과열시켜서 메인보드를 태워버리는 동작도 포함될 수 있습니다.
현실적인 얘기를 하자면, 그런건 본인컴에서 잘 돌아가도 다른 사람컴에선 그냥 segmentation fault로 죽어버리는 경우도 많습니다. 아무것도 보장되어있지 않습니다.
?
메모리가 부족하다는 건 어디서 들은 내용인지 모르겠습니다만 지금 Debug 모드에서 실행하신 듯 한데
그렇게 할 경우 Release 에 비해 스택을 크게 할당합니다. 따라서 공간은 넉넉할 뿐더러 넘칩니다.
당연히 Debug 모드이면 1바이트만 넘쳐도 바로 오류를 표시하는 코드가 따로 있긴 합니다.
Release 라고 해도, 스택은 기본적으로 조금 더 크게 할당합니다. 따라서 공간은 여유있습니다.
그리고 제가 "할당" 이라고 했지만 결과적으로는 sub esp,0x? 와 같은 연산일 뿐입니다.
커널 레벨에서의 메모리 할당 개념이 아니라 이미 할당된 스택 메모리에서 포인터를 조절하면서 쓰는 것 뿐입니다.
따라서 넘쳐서 쓰는 것 자체는 아무런 문제도 없습니다.
또한 이는 new 로 할당한, 즉 힙에도 똑같이 적용됩니다. 그리고 더불어 new char[3] 을 했다고 해서
정말로 3바이트 블록을 할당할 거라고 생각하시지는 않겠지요. 운영체제는 언제나 페이지 단위로, 또는 그 이상으로 할당합니다.
즉 각 메모리 청크는 실질적으로 더 크게 할당받고 있기 대문에 Access Violation 은 더 크게 넘치지 않는 한 뜨지 않습니다.
?
덧붙여서 힙 역시 마찬가지로 Debug 일 경우에는 1바이트만 넘쳐도 Heap Corruption 오류를 메시지로 표시해줍니다.
그러나 실제 Release 에서는 그런 게 없기 때문에 그냥 쓸 수 있을 때까지 계속 쓸 수 있습니다.
또한 보통의 경우 사이 사이에 각 메모리 청크에 대한 정보(보통 Linked List로 구현하므로 노드 포인터도 포함)가 있기 때문에
이런 것을 잘못 덮어쓰게 되면 다음 new/delete 와 같은 할당 시에 오류가 발생할 수 있습니다.
물론 이를 이용한 Heap Overflow 도 있습니다.
얼마 전 Plaid CTF 의 ezhp 라는 문제가 그런 류의 취약점이었습니다.
좀 오래된 글이지만,
좀 오래된 글이지만,
https://kldp.org/node/1073
이것도 참고해보세요.
---
http://coolengineer.com
댓글 달기