문자열 복사, 붙이기 등의 내부 구현이 궁금합니다.

vi08의 이미지

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: 
첨부파일 크기
Image icon Cap 2014-05-14 17-03-47-813.png15.21 KB
klara의 이미지

그냥 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 라는 문제가 그런 류의 취약점이었습니다.

pynoos의 이미지

좀 오래된 글이지만,

https://kldp.org/node/1073

이것도 참고해보세요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.