[완료] C에서 헷갈리는 부분이 있어 질문드려요.

ystory의 이미지

안녕하세요.
그동안 그러려니 하고 넘어갔던건지 아니면 제가 뭘 잘못한건지 헷갈려서 질문드립니다.

#include <stdio.h>
 
int main()
{
    int i, arr[2];
 
    for(i = 0; i < 100; i++) {
        arr[i] = i;
        printf("%d\n", arr[i]);
    }
 
    return 0;
}

위와 같은 소스가 있습니다. 물론 이건 제가 헷갈려서 만든 잘못된 소스 입니다.
그런데 그동안 세그먼트 폴트가 처음에 선언한 배열의 크기를 넘어설 경우 나는걸로 알고 있었는데
위의 소스를 실행해 보면 arr[99] = 99까지 정상적으로 실행 됩니다.
즉, 배열 크기인 2를 넘어서도 당장은 에러가 나질 않습니다.
게다가 디버깅 해봐도 특이한 점을 찾을수 없었습니다.
그래서 for문의 종료 크기를 줄여봤지만 마찬가지였습니다.
그럼 질문드릴게요. 세그먼트 폴트의 정확한 의미가 무엇인가요?
어떤 의미에서의 overwrite를 말하는 건가요? 미리 만들어진 배열 크기가 있는데 그걸 넘어서는
것에 대한 overwrite? 아니면 할당되지 않은 메모리 공간에 대한 접근?
그리고 결론적으로 이러한 에러에 대한 디버깅 노하우좀 공개해 주세요. ㅠㅠ
그럼 수고하세요~

wsmrdo의 이미지

당연히 위험합니다.
변수 영역과 프로그램 영역이 같다면.
해킹의 오버플로우 공격이 내부로 부터 되는 거군요 ㅡ.ㅡ;;

비쥬얼 C 등에서 변수로 넣지 않고, 상수로 넣을때는 잘못 넣었다고 경고 메세지가 뜹니다만.

변수로 넣을때는... 컴파일러도 뭐가 들어가는지 알아보지 못하죠.
사람이 하는 수밖에요. 뭐. 컴파일러 잘만들면 저런것도 검출해 내겠죠.

이 소스에서는 일단 i의 범위가 지정되긴 하니까요.
이러한 버그는 역시 사람이 발견하는 수밖에 없을 듯 하군요.

arr 은 포인터 입니다.
arr[1] ==> *(arr+1) 이렇게 사용해도 된답니다. 음... 가끔 아닐때도 있습니다만.

선언부에 2개를 선언했으면 그만큼 공간을 확보하겠다는 말이고. 요 안에서만 쓰겠다 란 표현이죠.
컴파일러는 2개 공간만 확보합니다. 그 뒤로는 프로그램이 오던 다른 데이터 영역이 오던 하겠죠.

뒤에 에러날 이유는 없는 것입니다.

확보하지 않은 공간에 데이터를 써넣게 되겠죠. 그 공간이 뭐에 사용하는 공간이 될지는 모릅니다.
int main()
{

int i, arr[2], brr[100];

for(i = 0; i < 100; i++) {
arr[i] = i;
printf("%d\n", arr[i]);
}
for(i = 0; i < 100; i++) {
printf("brr[%d] == %d\n",i ,brr[i]);
}
return 0;
}

arr[2]와 brr[100]이 연속 공간에 확보 되었다면...

brr[x] 에는 x+2 의 값이 들어 있을 겁니다.

^^*

원하는 답인지 모르겠군요.
써놓고 보니 뭔소리인지 ㅎㅎㅎ

ystory의 이미지

아. 그렇군요. 그런데 제 의문점은 컴파일 타임에 컴파일러에 의해 스택에 공간을 확보하고
(위의 제 소스에서 arr의 경우 int형 변수 2개) 그 공간 이상의 데이터를 참조하거나 접근하고자
할때 커널에서 실행을 멈추고 세그먼트 폴트와 같은 오류를 내는 것으로 아는데
이것이 맞다면 논리적으로 잘못된 공간을 참조하는경우 바로 에러메세지를 보여줘야
하지만 실제로는(어쩌면 저의경우?) 그렇지 않고 확보된 공간을 넘어서도 정상적인 결과를 보이다가
마지막에 가서 오류를 보인다는 겁니다. 심지어 i 값을 바꾸어도 마찬가지구요.
디버깅 해서 i를 10으로 줬을때 a[9] = 9에 까지 정상적인 값이 들어가는걸 확인했습니다.
그런데 에러가 나는곳은 어이 없게도 return 하면서 에러 메시지를 뿌리더군요.
도무지 모르겠습니다. 어떻게 이해해야 할지. ㅠㅠ
참고로 gentoo-2.6.23-gentoo-r3, gcc 4.1.2 사용하고 있습니다.
--------------------------------------
으휴
mail@ystory.kr

--------------------------------------
으휴

익명 사용자의 이미지

메모리를 잘못 참조할 때 바로 에러를 내는 것이 디버깅 측면에서는 편하겠지만
런타임에 그것을 계속 추적하면 성능이 저하될 수밖에 없습니다.
C는 성능에 목숨을 거는 언어이기 때문에 프로그래머가 코딩한 대로 무조건 실행하는 거죠.
만약 잘못이 있다면 그 문제가 언제 발생할지 모르게 되는 거고요.

익명 사용자의 이미지

정의되지 않은 행동입니다.

"정해진 배열의 크기를 넘어서 액세스를 할때 바로 오류를 낸다."
라고 정해 놓았다면 이것도 정의된 행동이죠. ^^

하지만 오류를 내라거라 배열크기를 자동으로 확장하라거나 등등 그 어떠한 정의가 없습니다.

즉 그게 언제 문제로 터질지는 그래서 모르는 겁니다. 그러니 더 위험하죠. ^^

kalstein의 이미지

상당히 조심하셔야됩니다...

일반적인 PC에서의 C/C++상황에서는 상위처럼 에러를 내뿜고 코어덤프를 내기라도 하지요...
(덤프파일을 보고 분석할 수 있습니다.)

임베디드시장쪽으로 가면...그냥 CPU가 돌다말고 끝입니다 -_-;;;;
(뭐 OS가 지원한다면 다행이지만...지원못하는게 더 많아요;;)


------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/

ystory의 이미지

하지만 커널에서 오버플로우에 대해 오류를 낸다는건 이에대한 문제점을 인지하기 때문인데
왜 바로 오류를 내지 않고 잘못된 참조 인걸 알면서도 끝까지 진행을 하고 끝에서
에러 메세지를 내는 걸까요? 물론 위의 소스는 엉망으로 질문을 위해 만들었습니다.
질문에서도 말씀 드렸지만 커널에서 세그먼트 폴트를 발생시키는 기준이 무엇인지가 궁금합니다.
답변해주셔서 감사합니다.
--------------------------------------
으휴
mail@ystory.kr

--------------------------------------
으휴

익명 사용자의 이미지

일반적으로 C언어로 생성한 Binary의 스택에는 최소한 지역변수, 함수의 인자(parameter), 복귀 주소(함수의 수행이 종료된 뒤에 실행할 주소)가 들어가 있습니다. 문제는 스택의 구조가 역으로 자라는 구조라는 점 입니다. (push를 계속 할 경우 주소가 줄어드는 방향으로 진행합니다) C언어의 지역 변수는 자라는 방향의 가장 앞 부분에 위치합니다. 따라서 지역 변수에서 선언한 배열의 크기보다 큰 데이터를 기록하면 뒷 부분의 주소에 저장되어 있는 복귀 주소가 파괴될 수 있습니다. 따라서 복귀 주소가 사용되기 전의 함수까지는 잘 수행되다가 (물론 인자 값을 사용하는 함수들은 오작동 내지 잘못된 결과를 반환하기 시작합니다) 복귀 할 때 엉뚱한 주소로 분기합니다. 이렇게 되면 대개는 할당되지 않은 메모리 주소로 실행 시점을 옮겨버립니다. 따라서 할당되지 않은 페이지를 참조한 결과로 세그먼트 폴트가 발생합니다.

ystory의 이미지

와우~~~~~감사합니다.
정말 명쾌한 해설이었습니다. 이제 좀 이해가 되네요.
그런데 한가지 더 의문점이 있다면 커널이 메모리의 오버플로우를
감시하거나 중단 시키는 역할은 하지 못하는 건가요?
그렇다면 애초에 프로그래밍할때 방지 하는 방법 밖엔 없는건가요?
--------------------------------------
으휴
mail@ystory.kr

--------------------------------------
으휴

익명 사용자의 이미지

최소한의 가상 메모리 페이지 단위까지는 침범을 확인하겠지만 그 이하로 관리하려면 자원이 너무 많이 소모되니 그렇게 하지 않는 것입니다. 결과적으로 세부적인 관리는 프로그래머 또는 컴파일러의 몫이 됩니다. 애초에 신경을 쓸 필요가 없는 언어를 선택하거나 프로그래머가 잘 신경써주거나.. 둘 중의 하나가 됩니다.

ystory의 이미지

감사 합니다.
고민 해결 됐습니다. ㅎ
--------------------------------------
으휴
mail@ystory.kr

--------------------------------------
으휴

coathanger의 이미지

음.. 그렇군요...

d3m3vilurr의 이미지

gcc의 특정버전부터 배열에 더미를 추가해 줍니다.
특정한 규칙으로 더미가 추가됐던것으로 기억됩니다.
명백한 메모리 낭비이지만, 그럭저럭 bof exploit을 방지하는 한가지 방법이 되기도 했을겁니다.
또한 개발자의 하나차이의 오류를 어느정도 보완해줬을거고요.

저 경우는 위의 버퍼 추가나 우연하게 뒤의 영역까지 쓰기가능한 빈 메모리 영역으로 할당되어 있을 가능성이 높아보입니다.
그리고 함수 종료시에 에러가 나는것은, main의 ret 영역이 덮어져서 에러가 나는 것으로 추측할 수 있을 것 같습니다.

그 외의 설명은 윗분들이 잘 해주셨으니까 :)

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.