배열 첨자 초과 문제

kcho의 이미지

C 언어 프로그램 상에서 배열 첨자를 초과하는 오류를 범해도 경고나 오류 없이 프로그램이 계속 실행되더군요. 배열의 첨자 초과시 오류 메시지를 출력하면서 프로그램을 종료시키는 함수나 클래스 같은 것 좀 소개해 주세요.

winner의 이미지

C 로 하자면 잘 사용하지 않는 기술로 signal 함수를 사용해서 작성하신 signal handler 를 등록하는 것입니다.

객체지향 program 에서는 예외처리라는 것이 있습니다.

compiler 에 따라서 배열 index 의 경계값을 검사하게 하는 것이 가능합니다.
compiler 도움말을 읽어보시면 compile option 에 있을 것입니다.
사용해 본 적이 없어서 결과가 어떻게 나오는지는 모르겠군요... -_-
잘은 모르겠습니다만 위에서 말한 signal 이 발생하지 않을까 싶은데...

세벌의 이미지

cc -Wall 로 테스트해봤는데 배열 첨자 범위를 넘어가는 것 체크하지 않는군요. 컴파일러 차원에서 검사할 수 있는 방법은 없는지 궁금해지는군요.

envia의 이미지

----

It is essential, if man is not to be compelled to have recourse, as a last resort, to rebellion against tyranny and oppression, that human rights should be protected by the rule of law.
[Universal Declaration of Human Rights]

douner의 이미지

STL 의 vector 를 사용하는 것이 어떨까요...
vector 에 원하는 기능은 없지만(속도를 빠르게 하기 위해서 에러 검사와 예외 처리는 거의 없습니다) 다른 멤버 함수 등으로 범위 체크를 충분히 할 수 있을 것 같네요.

인생, 쉬운 것만은 아니네..

체스맨의 이미지

C 언어처럼 포인터 사용이 자유로운 언어는 컴파일 단계에서
이런 오류를 검사할 수 있는 방법이 없습니다.

C 포인터는 전적으로 개발자가 책임지는거죠. 잘해도 못해도
개발자 탓입니다. 권한도 큰만큼 의무도 큰거죠...

signal handler 나 C++ 예외처리로도, 개발자가 잘 못사용한
길잃은 포인터를 해결해 줄 수 는 없습니다. segfault 가 발생하지
않는 영역에서 쓰거나 읽었더라도 잘못된 포인터 사용일 수 있으니까요.

Orion Project : http://orionids.org

mach337의 이미지

ElectricFence 를 사용하면 디버깅할때 편하더군요.
아래와 같은 Code 가 있다면

char *ptr = (char *)malloc(1024);
ptr[0] = 0;
ptr[1024] = 0;

ptr[1024] = 0; 여기서 멈춥니다.
그런데 일반 배열선언된 변수를 사용하게 되면 안되더군요.

akbar의 이미지

김형 wrote:
STL 의 vector 를 사용하는 것이 어떨까요...
vector 에 원하는 기능은 없지만(속도를 빠르게 하기 위해서 에러 검사와 예외 처리는 거의 없습니다) 다른 멤버 함수 등으로 범위 체크를 충분히 할 수 있을 것 같네요.

STL 의 vector 의 멤버 함수를 사용하면 범위 체크를 충분히 할 수 있다면
STL 을 쓰지 않았을 때도 범위 체크 코드를 두면 그만입니다.
STL 을 쓰고 안쓰고의 문제가 아닙니다.
정말 문제는 속도에 민감한 프로그램에서는 범위 체크 코드를 두면
그만큼 오버헤드가 발생한다는 것이죠
보통 C++ 에서 잘 짜여진 클래스들은 범위 체크 코드를 두게 되는데
그 클래스를 여러 번 상속했을 경우에
오버헤드 문제가 심각해질 수 있습니다.
만일 클래스 CTest 의 멤버함수 m_f1() 에 어떤 문자열이 있고
인수를 전달받을 때 인수가 문자열 범위를 벗어났는지를 검사하는 경우
이 클래스를 상속 클래스에서 재생해서 m_f1() 를 내부적으로 호출하고 있다면
그 재생함수에서 또다시 에러 체크 코드를 두어야 할까요.
만약 에러 체크 코드를 두지 않아서 m_f1() 를 호출하기 전에
에러가 날 경우가 많아진다면 또 어떻게 해야 할까요

파생클래스의 재생 혹은 중첩함수가
이미 에러나 범위 체크 코드가 있는 기본클래스의 맴버 함수를 호출해야 하는 경우
재생(이나 중첩) 함수에서 자칫 쓸데없이 에러체크 코드를 두어
에러 체크를 두번 이상 하게 되는 경우가 발행할 수 있습니다.
(속도가 민감한 프로그램의 경우에...)
상속이 여러 번 행해지면 세네번 그 이상 반복적인 에러 체크 코드가 놓여 질 수
있으므로 주의해야 합니다.

dudungsil의 이미지

제목 그대로네요. Valgrind를 친구목록에 추가 시키면 그런 문제는 대부분 해결될겁니다.

산넘어 산

winner의 이미지

배열 index 경계는 compile time 이 아니라 runtime 에 수행되어져야 합니다.
index 가 상수만이 아니라 변수가 사용될 수 있으니까요.
Lint 는 이런 문제를 미리 검토해서 보고하는 program 으로 알고 있습니다.
써본 적은 없습니다만...

Java 는 제 기억이 맞다면 OutOfBound 라는 예외를 발생시킬 것입니다.
C++ STL container 에는 at member 함수가 있는 것으로 압니다.
GCC 에 탑재된 SGI STL 에서는 string 만 지원하는데 [] 연산자함수와는 달리 index 경계 예외를 발생시킵니다.

C 에서는 예전에 Turbo C 2.01 을 사용해본 적이 있습니다.
16bit compiler 라 만들어지는 실행 code 가 Windows 2000 이상에서는 호환mode 를 왔다갔다 하느라 화면이 이상해지는 것을 보고 안 쓰게 되었는데 거기서는 배열 index 경계에 대한 option 이 있었습니다.
(사용한 적은 없습니다만...)

그런데 GCC 에서는 안 보이더군요.

mach337 wrote:
ElectricFence 를 사용하면 디버깅할때 편하더군요.

전에 mach337 씨가 쓴 글을 보면 이에 해당하는 option 은 -lefence 인 것 같은데 제가 사용한 GCC 2.96 과 3.3.2 는 그런 option 이 없는 것 같습니다.

l 이 붙는 것으로 봐서는 shared object 인 것 같은데...

http://gcc.gnu.org/onlinedocs/gcc-3.3.3/gcc/Code-Gen-Options.html#Code%20Gen%20Options
GCC 3.3.3 Documentation 을 보면 -fstack-check 와 -fbounds-check 라는 것이 있습니다.

여기서 얘기되는 index 경계는 -fbounds-check 를 써야 할 것 같은데 Fortran77 과 Java 만 지원한다는군요...

저도 처음 programming 시작할 때 항상 문제는 배열 index 였던 것으로 기억합니다. pointer 와 동적할당을 배우고 나서는 pointer 쓰기가 겁났던 적도 있습니다. Pointer 가 사용되는 programming 을 시작 할 때면 언제나 이거 debugging 할 때 죽어나겠군이라는 생각을 했죠.

최근에는 coding 하기 전에 좀더 신중히 생각해보는 버릇이 생겨서 오류도 적어져고 이제는 겁은 안납니다만 여전히 coding 할 때 pointer 와 index 는 신중히 검토하게 됩니다. C++ 와 STL 을 공부하면서 얻은 이득은 단지 library 의 활용만이 아니라 구간에 대한 개념이 정형적으로 잡혔다는 것입니다.
Pointer 를 반복자처럼 사용하는 제 자신을 보면 가끔 묘한 기분이 듭니다.
사실 이런 pointer 의 정형적인 사용기법과 구간개념은 C Programmer 들에게도 있더군요. STL 의 개념이 건너간 것인지는 모르겠습니다만...

[quote="dudungsil
"]Valgrind를 친구목록에 추가 시키면 그런 문제는 대부분 해결될겁니다.
Valgrind 가 뭐죠? 이전에 dudungsil 씨가 쓰신 글을 보면 광고는 아닌 것 같고...
농담인지... 아니면 속뜻을 품고 있는 진담인지... ???

akbar 씨의 글을 읽으니 예전에 본 예외처리 논쟁이 기억납니다.
제목만 읽고 본문은 안 읽었습니다만... -_-
예외처리는 객체지향 Programming 언어의 대부분이 지원하는 지금에 와서도 좋은 기술인가하는 논쟁이 있는 것 같습니다.

mach337의 이미지

winner wrote:
mach337 wrote:
ElectricFence 를 사용하면 디버깅할때 편하더군요.

전에 mach337 씨가 쓴 글을 보면 이에 해당하는 option 은 -lefence 인 것 같은데 제가 사용한 GCC 2.96 과 3.3.2 는 그런 option 이 없는 것 같습니다.

l 이 붙는 것으로 봐서는 shared object 인 것 같은데...


물론 ElectricFence 를 설치해야 합니다.
saxboy의 이미지

흠... 이 문제는 C나 C++에 익숙해지기 위해서는 꼭 한번 짚고 넘어가야 하는 문제입니다. 모 잡지에 C기사를 하나 연재하고 있는데, 지난 달과 이번 달에 두회에 걸쳐서 적었던 내용이 이것과 꽤 많이 관련이 있습니다. 혹시 궁금하시면 잠깐 읽고 잊어버리셔도 좋을 듯 싶습니다.

결론적으로 array의 index나 invalid한 pointer나 같은 문제가 되고 런타임이 아니라면 체크가 불가능합니다. 따라서 메모리 디버거라는 별도의 런타임 디버거들이 의미를 가지게 되는 것이지요. 프로그램의 종류에 따라 다르지만 index의 체크나 leak의 체크를 함께 해주도록 구성되어 있습니다.

자주 쓰이는 메모리 디버거에는 valgrind, mpatrol, yamd, ElectricFence, memprof 등등이 있겠지요. VC++을 사용하는 윈도우 환경에서라면 BoundsChecker라는 걸출한 디버거가 있습니다.

이것과는 별도로 컴파일타임에서 컴파일러가 찾아주지 못하는 오류를 검사하기 위해 문법을 철저하게 검사해주는 것을 static analysis라고 하고, lint 가 대표적인 프로그램에 속합니다.

게시판에서 메모리 디버거나 valgrind같은 단어로 검색해보신다면 꽤 여러개의 스레드를 찾으시리라 믿습니다.

조금 더 여유가 되신다면 이런 런타임 메모리 체크를 어떤 식으로 구현하는지 생각해보셔도 좋겠습니다. 프로그램이 실행하면서 메모리를 어떻게 사용하는지에 대해 많은 유용한 개념을 얻으실 수 있습니다.

dudungsil의 이미지

Quote:

Valgrind 가 뭐죠? 이전에 dudungsil 씨가 쓰신 글을 보면 광고는 아닌 것 같고...
농담인지... 아니면 속뜻을 품고 있는 진담인지... ???

saxboy님 글 중간에 나왔듯이 메모리 디버거입니다. 메모리에 관련된 다양한 문제를 쉽게 찾아 낼수 있습니다. 아직 사용해 보지 않으셨다면 윗글대로 친구목록에 추가해보세요. 프로그래머의 좋은 친굽니다.

http://valgrind.kde.org

에서 찾으실수 있습니다.

산넘어 산

saxboy의 이미지

Quote:
파생클래스의 재생 혹은 중첩함수가
이미 에러나 범위 체크 코드가 있는 기본클래스의 맴버 함수를 호출해야 하는 경우
재생(이나 중첩) 함수에서 자칫 쓸데없이 에러체크 코드를 두어
에러 체크를 두번 이상 하게 되는 경우가 발행할 수 있습니다.
(속도가 민감한 프로그램의 경우에...)
상속이 여러 번 행해지면 세네번 그 이상 반복적인 에러 체크 코드가 놓여 질 수
있으므로 주의해야 합니다.

순전히 제 생각입니다만, 저는 이런 에러체크에 대한 오버헤드를 걱정할 필요는 별로 없다고 생각합니다. 할 수 있는 한의 에러체크는 모두 해주는 것이 좋다는 생각입니다. 컴퓨터는 생각보다 빠르던데요. :-)

보통 performance와 에러체킹의 오버헤드사이의 균형을 맞추기 위해 많이 사용하는 것이 assert와 NDEBUG 가 되겠습니다만, 저는 DEBUG flag으로 최종 바이너리에서는 assertion을 없애버리는 것보다는 가능한만큼 에러체킹을 해서 리턴으로 런타임에 에러를 돌려주는 것을 선호하는 편입니다. 원체 메모리에 제약이 없는 언어이니 그 정도는 감수해야 한다고 믿는 것이지요.

하지만, 포인터라는 개념이 전혀 없는 스크립트 언어나 다른 종류의 라이브러리에도 이정도의 에러체킹 루틴은 이미 포함되어 있습니다. 리눅스 커널 소스는 어떤 함수가 되었건 거의 무조건 포인터 널체크부터 시작하지요. :-)

winner의 이미지

Product 에 assertion 을 빼는 것은 연습할 때는 중무장을 하고, 실전에서는 모두 벗어버리는 것과 같다. --- Tony Hoare.

정확한 문장은 기억이 안 납니다만 대충 이런 말이었던 것으로 기억합니다.
서양과는 달리 일본의 검술은 몸을 가볍게 해서 빠르기를 중요시하는 경향도 있습니다만... -_-

'Writing Solid Code' 의 저자 Steve McGuire 는 Micorsoft 의 software 개발국장이었다는데 assertion 을 쓰라고 치열하게 싸웠다는군요.

댓글 달기

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