찾기 어려웠던 버그들...

서지원의 이미지

이 글타래에서는 구체적인 프로그래밍 버그 예에 대해서 이야기하면 안될까요? 누구때문에 고생했다거나 하는 신변잡기적인 이야기나 하소연(?) 등은 다른 글타래에서도 많이 하니까 굳이 따로 모아서 여기서 이야기할 필요는 없을 것 같습니다. 여기서는 구체적인 프로그래밍 버그에 대해서 집중해서 이야기했으면 좋겠네요.

프로그래밍에서 보통 디버깅이 가장 리소스(시간, 돈 등등)를 많이 잡아먹는 단계중의 하나인데요,
자신이 경험했던 버그들에 대해서 리포팅해 보는 글타래를 하나 만들어 보는것도 좋을 것 같습니다.

자신을 괴롭혔던 버그나, 많이 경험했던 버그 패턴 등등을 자세한 예와 함께 나열/토론해 보면 서로에게 많은 도움이 되지 않을까 합니다.
실제 예를 가지고 이야기하는 것이 가장 좋겠지요. (이 글타래에서는 프로그램 버그에 대해서 집중했으면 합니다. 하드웨어 버그나 등등은 따로 글타래를 여는게 좋을 것 같습니다)

제 경우는 최근에 다음과 같은 버그로 약간 고생했습니다.

Python code에서,

class Foo(object):
    classVar1 = None
    classVar2 = []
    ...
    def classMethod(cls):
        cls.classVar1 = "Foo"
        cls.classVar2.append("Foo")
 
class Bar(Foo):
    @classmethod
    def classMethod(cls):
        cls.classVar1 = "Bar"
        cls.classVar2.append("Bar")
 
Foo.classMethod()
Bar.classMethod()

위 코드를 실행하면, Foo.classVar1, Bar.classVar1 은 각각 "Foo", "Bar"를 가지게 되지만, Foo.classVar2, Bar.classVar2 는 ["Foo", "Bar"] 라는 동일한 값을 가지게 됩니다. 저는 classVar1, classVar2를 위처럼 선언하면 class variable이 되는줄 알았는데 (즉 subclass도 독립적인 variable을 가지게 되는줄 알았는데) classVar1, classVar2는 Foo에만 선언되고, 저 variable들은 Foo와 Bar에서 공유하게 됩니다.

문제는 Bar.classVar1="Bar" 라고 하는 순간에는 새로 Bar class의 variable을 추가하게 되는데, Bar.classVar2.append("Bar") 라고 하게 되면 Foo의 classVar2(list type) 에다가 "Bar"만 하나 추가하게 됩기 때문에, 마치 classVar1은 독립적인 variable로 보이고 classVar2는 공유되는걸로 보여서 헷깔립니다.

실제로 제가 원하는걸 하려면 metaclass를 써서 다음처럼 해야 합니다. (다른 간단한 방법이 있을수도 있음...)

class MyType(type):
    def __new__(cls, name, bases, dict):
        klass = type.__new__(cls, name, bases, dict)
        klass.classVar1 = None
        klass.classVar2 = []
class Foo(object):
    __metaclass__ = MyType
 
class Bar(Foo):
    pass

위처럼 자신이 경험했던 최악의/흔한/재밌었던/어려웠던/... 버그들에 대해서

1. 구체적인 코드
2. 왜 찾기 힘들었는지
3. 그리고 가능하다면 어떻게 하면 좀더 쉽게 찾을 수 있었을까 (예를들면 memory leak인 경우에는 valgrind를 쓴다던지... 아니면 어떤 특정한 기능의 tool같은게 있었으면 쉬웠을 것 같다던지...)

에 대해서 한번 이야기해 보면 서로에게 많은 도움이 될 것 같습니다.
(꼭 저 형식을 따를 필요는 없겠지만, 이왕이면 자세하게 적는것이 좋겠죠)

지리즈의 이미지

몇해전인가?
제가 관리하고 있는 서버가 갑자기 네트워크가 안되는 것입니다.

이전부터 온보드 랜카드의 드라이버가 불안정해서
수차례 이러한 증상을 겪어 왔지만,
두어달전 커널을 업데이트한 이후로 더 이상 증상이 나타나지 않았던 터라
더 좌절감이 느껴졌죠.

이 이후로 커널을 재컴파일 해보고...
네트워크 설정을 바꾸어 보고,
심지어면 온보드가 아닌 다른 랜카드를 사용해도 여전히 네트워크가 안되는 겁니다.

도저히 원인을 규명하지 못하고 IDC에서 24시간을 꼬박지낸다음...
우연히 케이블을 바꿔 보니 네트워크가 되는 겁니다 ㅠ.ㅠ.

그렇습니다

애초부터 드라이버가 불안정한게 아니라,
랜선이 불량이었던 거죠. -_-;;;

우연히 커널 업데이트 이후 문제가 한동안 잠잠했기 때문에
랜선 불량이라고 감히 생각을 못했던게 -_-;;;

There is no spoon. Neo from the Matrix 1999.

There is no spoon. Neo from the Matrix 1999.

angpang27의 이미지

에프슬트엔들피..............
일곱가지 레이어랍니다.............

정말 아쉽군요

고통이 지천에 있다한들 어이해 멈출수있더냐

bacchusf의 이미지

for (int i=0; i < n;i++)
  for (int j=0;i < n;j++)
    for (int k=0;k < n;k++)
      // do something

저 버그로 고생한 이후로는
#define forloop(index, bound) for (int (index) = 0;(index) < (bound); (index)++)
 
forloop(i,n)
  forloop(j,n)
    forloop(k,n)
      // do something

으로 해서 씁니다.
FIFO의 이미지

무슨 버그가 있는건가요...? 설명해주시면 고맙겠습니다.

slee0303의 이미지

두번째 루프에서 j가 i로 바뀌어 있네요.

FIFO의 이미지

정말 찾기 어려운 버그군요~

jonghyunee의 이미지

위와동문.. ㅠㅠ;;

warpdory의 이미지

학교 다닐 때, 아르바이트 비슷하게(근로장학생 ... ) 학교 전산망을 관리했었는데...

어느날 학교내부에서는 잘 되는데, 밖으로 나가는 게 안돼서 난리가 난 적이 있었습니다.

여기 저기 뛰어 다니며 원인을 찾았는데...

알고보니, 최종 라우터(학교 밖으로 나가는 바로 직전에 있는 것) 의 전선을 뽑고, 거기에 핸드폰 충전기 꽂고 핸드폰 충전하고 있더군요 ...

........ 땅파고 묻어 버릴까 .. 라는 생각까지 했었습니다.

---------
귓가에 햇살을 받으며 석양까지 행복한 여행을...
웃으며 떠나갔던 것처럼 미소를 띠고 돌아와 마침내 평안하기를...
- 엘프의 인사, 드래곤 라자, 이영도

즐겁게 놀아보자.
http://akpil.egloos.com


---------
귓가에 햇살을 받으며 석양까지 행복한 여행을...
웃으며 떠나갔던 것처럼 미소를 띠고 돌아와 마침내 평안하기를...
- 엘프의 인사, 드래곤 라자, 이영도

즐겁게 놀아보자.

rainroot의 이미지

상상만 해도 열받는군요..ㅋㅋㅋ

저도 잠깐 전산망비슷한걸 관리한적 있는데.. ㅋㅋ 위와같은 상황 발생하면

묻어버렸을 겁니다..

NoSyu의 이미지

c'est un des orgueils de notre pauvre humanité, que chaque homme se croie plus malheureux qu'un autre malheureux qui pleure et qui gémit à côté de lui
- Le Comte de Monte-Cristo
-----------------------------------------------------------------------

무얼 묻어 버릴 생각이셨습니까?!

c'est un des orgueils de notre pauvre humanit?, que chaque homme se croie plus malheureux qu'un autre malheureux qui pleure et qui g?mit ? c?t? de lui
- Le Comte de Monte-Cristo
-----------------------------------------------------------------------

slee0303의 이미지

당연히 라우터겠죠.

FIFO의 이미지

'코렐라인' 보셨어요? 반갑습니다

dosuser의 이미지

뿜었습니다.

프로그래머 다운 프로그래머가 되고 싶습니다. 많은 지도 편달 부탁드립니다^^

프로그래머 다운 프로그래머가 되고 싶습니다. 많은 지도 편달 부탁드립니다^^

warpdory의 이미지

라우터 전원 뽑고 핸드폰 충전하던 교직원이었습니다.

ps. 이 양반이 한 짓중 대박은, 서버실에 짱박혀서 잠자다가 팬소리 시끄럽다고 UPS 전원을 꺼버린 거였습니다.

---------
귓가에 햇살을 받으며 석양까지 행복한 여행을...
웃으며 떠나갔던 것처럼 미소를 띠고 돌아와 마침내 평안하기를...
- 엘프의 인사, 드래곤 라자, 이영도

즐겁게 놀아보자.
http://akpil.egloos.com


---------
귓가에 햇살을 받으며 석양까지 행복한 여행을...
웃으며 떠나갔던 것처럼 미소를 띠고 돌아와 마침내 평안하기를...
- 엘프의 인사, 드래곤 라자, 이영도

즐겁게 놀아보자.

narisoso의 이미지

아무리 설명해도 그 교직원은 그 사태의 심각성을 모르겠죠.....
그게 미치는거죠.

죠커의 이미지

그 돌아이는 어떻게 되넜나요?

- 죠커's blog / HanIRC:#CN

warpdory의 이미지

전산실 담당도 아니고 .. 그냥 일반 행정직원이라서 ...
아마 불려가서 구박 좀 받고 끝났던 걸로 기억합니다.

대신, 그거 밑에서 조교들이 수습하느라 개고생 했었죠.

---------
귓가에 햇살을 받으며 석양까지 행복한 여행을...
웃으며 떠나갔던 것처럼 미소를 띠고 돌아와 마침내 평안하기를...
- 엘프의 인사, 드래곤 라자, 이영도

즐겁게 놀아보자.
http://akpil.egloos.com


---------
귓가에 햇살을 받으며 석양까지 행복한 여행을...
웃으며 떠나갔던 것처럼 미소를 띠고 돌아와 마침내 평안하기를...
- 엘프의 인사, 드래곤 라자, 이영도

즐겁게 놀아보자.

bushi의 이미지

낙하산이었나 보군요.

OTL

서지훈의 이미지

개그 소재로도 전혀 손색이 없네요 ㅎㅎ;

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

indeok84의 이미지

님 코드가 멋져서 제 미니홈피에 허가없이 인용했습니다.
싫으시다면 말씀주세요. 지우겠습니다~ ㅋ

나빌레라의 이미지

명료하게 떨어지는 버그는 아지만,

최근 몇년 통털어 가장 격하게 했던 삽질을 블로그에 적어 놓은게 있습니다.

http://maanu.net/soojung/entry.php?blogid=382

스크롤의 압박이 있긴 하지만, 읽어보면 재밌기도 합니다...^^

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

처로의 이미지

재미있다기보다 눈물이 앞을 가리는군요. 무수면 60시간만의 쾌거. ㅠㅠ

systemfile의 이미지

회사에서 처음으로 간단한 프로그램을 하게 되었습니다.
실제 사용될거라 많이 긴장했었는지 버그에 직면하고 괭장히 당황했었습니다.

파일 읽어오는 부분을 만들었는데 같은 값을 두번씩 읽어오는 겁니다.
결국 다른 부분은 다 삭제하고 해봤는데도 그랬습니다.

답은 다른 파일을 읽어오고 있었던 거였습니다.

제 평생 가장 고치기 힘들었던 버그였습니다

: D

NoSyu의 이미지

c'est un des orgueils de notre pauvre humanité, que chaque homme se croie plus malheureux qu'un autre malheureux qui pleure et qui gémit à côté de lui
- Le Comte de Monte-Cristo
-----------------------------------------------------------------------

학교 수업 프로젝트로 친구와 코딩하였습니다.

그런데 자꾸 메모리 오류가 나기에 디버깅을 해보았습니다.

하지만 아무리 살펴봐도 메모리 오류로 죽어버리기 앞 10줄 정도를 살펴보았지만 전혀 문제가 없었습니다.

정확하게는 메모리 오류가 날 이유가 전혀 없었습니다.

그래서 자신의 코드 오류는 찾기 힘드니 서로 상대방의 코드를 읽어보면서 문제점을 찾기로 하였습니다.

결론부터 말씀드리면 배열 boundary 문제였습니다.

그것 때문에 저 멀리 있는 메모리 주소에 접근하여 에러가 난 것입니다.

그 에러의 이유는 코딩 문제가 아니라 소통 문제였습니다.

해당 배열은 크기가 3인 배열이었고, index를 그 친구가 만든 함수 인자로 하여 제가 만든 함수에서 call하는 방식이었습니다.

전 계산을 편하게 하라고 0부터 2까지 보냈고,

그 친구는 index라는 생각에 1부터 3까지 들어온다고 생각한 것입니다.

하지만 배열 접근을 위해서 인자로 들어온 index 값에 -1을 하여 배열에 접근하였기에

저 멀리 있는 메모리에 접근한 것입니다.

신기했던 것은 왜 그 때 에러가 나지 않고 한참이 지나서 에러가 났는지 궁금하더군요.

이래서 디버깅이 어렵다 + 소통이 어렵다는 것을 알았습니다.OTL...

c'est un des orgueils de notre pauvre humanit?, que chaque homme se croie plus malheureux qu'un autre malheureux qui pleure et qui g?mit ? c?t? de lui
- Le Comte de Monte-Cristo
-----------------------------------------------------------------------

fruitsclipper의 이미지

C++ 에 가슴아픈 추억이 많네요..

메모리 관리를 편하게 하려고 smart pointer 를 사용하였는데,
dead lock 걸리는 상황처럼 쌍방 참조가 일어나버렸습니다.

이것이 좀 복잡한 단계를 거쳐서 서로 참조가 일어나버린거라 쉽게 찾기가 힘들었죠..
모니터에 코드를 뚫어져라 쳐다보고 있었는데.. 갑자기 코드에서 빛이 보이는 겁니다. 그렇게 발견했습니다.. -_-;

두번째는 생성자나 소멸자에서 그 클래스에 속해있는 가상함수를 호출한 경우였는데요..
이것도 딱 눈에 보이는 상황이 아니라,
템플릿의 사용과 다중상속을 이용한 복잡한 상속관계 등으로 이리 저리 얽혀있는 경우에 일어나서
역시 모니터에 코드를 뚫어져라 쳐다볼 수 밖에 없었던...

codebank의 이미지

C/C++일 수도 있고 다른 언어도 비슷한 경우가 있을 수 있습니다.

네트워크에 관련된 문제입니다만 Debug 모드와 Release 모드에서 동작의
차이점이 발생하는 경우이죠.
자주 발생하지는 않지만 한번 이런일을 겪고나면 쉽게 잊어버리고 그 원인도
잘 모르는 문제인걸로 알고 있습니다.
사연은 이렇습니다.

고종 사촌형님의 회사에서 임시로 SI를 하고 있을 때 입니다.
형님 회사 사원한명이 하소연을 하는 겁니다.
어느 공기업쪽에 들어가서 프로그램을 작성해줬는데 Debug를 돌릴 때는
잘 돌아가다가 꼭 Release만하면 이상하게 통신쪽에서 제대로된 통신을
하지 못하다고요...
그래서 Debug와 Release할 때의 차이점이 무엇인지 물어봤더니 차이점은
없다는 겁니다. 다만... 어떤값을 주고 받는지 확인하기 위해서 화면에
printf를 이용해서 로그값을 보여준다고 하더군요.
그때 갑자기 UNIX의 file 처리방식에 대한 부분이 생각나더군요.
UNIX는 모든 장치들을 하나의 file처럼 생각하고 비슷한 처리방식을 가지고
있다라고 어느 책에선가 읽었던 기억이 스치는 것입니다.
그래서 혹시 Network도 하나의 파일을 처리하는 방식처럼 일정한 버퍼를
가지고 그곳에 쌓아 놓고 있다가 버퍼가 넘치거나 버퍼를 비우라는 메시지가
도착하면 데이터를 송신하는 것이 아닌가하는 생각이 들더군요.
그래서 send()또는 write()를 하고나서 fflush(stdout)을 써놓으라고
했습니다. 나중에 결과를 들어보니 정상적인 송수신을 한다고 하더군요.
(stdout을 fflush()하는 이유는 첫 번째로 네트워크에 관련된 장치명이
뭔지 몰라서였고 두 번째는 printf()가 화면 버퍼를 비우는 -화면에 출력
하는- 일을 하기 때문에 네트워크 버퍼도 비울것이라는 추축을... :-))

이후에 이것과 비슷한 문제들을 몇번 경험하고 나서 습관처럼 write()또는
send()를 쓸일이 있으면 반드시 fflush(stdout) 또는 해당 소켓 값을
(fflush(s_c)) 써넣게 되더군요.

---------------------------------------------------------------
최근에 임베디드 때문에 겪은 일도 한가지...
이 부분은 프로그램쪽의 문제이기 보다는 OS의 환경문제입니다.

보통 한가지 프로그램에서 파일을 열고 사용하고 파일을 닫는 것이 기본입니다.
이부분은 메모리쪽도 마찬가지일겁니다.
그런데 프로그램이 하나만 실행되는 상태에서는 별문제 없지만 여러 프로그램이
동시에 실행되어야만 하는 멀티 태스킹에서는 문제가 발생할 수도 있습니다.
제가 프로그램을 실행시킨 OS가 최근에 많이 사용되는 U...로 시작하는 OS였습니다만
(정확한 OS이름은 잘모르겠네요. 관심이 별로 없어서... :-))
이상하게 프로그램을 실행하면 자꾸 파일 Open쪽에서 문제가 생기는 겁니다.
코드를 확인해도 별로 이상이 없고 이전 파일들도 반드시 close되는 것을 확인했는데도
말입니다.
결국은 OS담당하는 분들이 제 프로그램에 문제가 있다며 Log를 보여주는데 이상하게
13번째 파일을 Open할 때 에러가 발생하더군요.
그때 생각났던것이 예전 MS-DOS시절에 File Open갯수를 12개만 가능하도록해서 그보다
많은 파일을 열기 위해서는 그 값을 Config.sys나 autoexec.bat에서 수정했었던
기억이 나더군요.
결국은 OS를 담당하시는 분에게 알려서 일단 30개까지 열 수 있도록 수정했고 이후에
더이상 그런 현상은 발생하지 않았죠.

File open할 수 있는 갯수가 정해져 있다는 것을 알지 못했다면 모든 책임이 저한테
넘어올 수 있었을지도 모르는 상황이었습니다만 많지 않은 경험중에서 겪었던 몇가지
일 때문에 책임을 지지 않아도 되었던 기억입니다.

이번일로 기초는 확실히 중요한 것이 아닌가하는 생각이 다시한번 들더군요. :-)
------------------------------
좋은 하루 되세요.

------------------------------
좋은 하루 되세요.

Fe.head의 이미지

재미있는 내용이군요.

socket을 fflush 한다라는건 처음보는거라^^

-----------------------
과거를 알고 싶거든 오늘의 네 모습을 보아라. 그것이 과거의 너니라.
그리고 내일을 알고 싶으냐?
그러면 오늘의 너를 보아라. 그것이 바로 미래의 너니라.
-----------------------
내가 쓰는 글은 틀릴 수 있습니다.

고작 블로킹 하나, 고작 25점 중에 1점, 고작 부활동
"만약 그 순간이 온다면 그때가 네가 배구에 빠지는 순간이야"

winner의 이미지

저는 보통 개발할 때 Release에서 하고 Debug는 debugger를 활용할 때만 쓰는 이상한 버릇이 생겼죠.
TDD와 logging을 하면서 debugger의 사용이 줄어들면서 생긴 버릇인데요.
뻗어야 할 때 뻗어주지 않는 Debug 때문에 bug를 발견하는 때가 늦춰져서 찾기가 어려워지는 경향이 있기 때문입니다.
한번은 Release에서 뻗어줘야 하는데 안 뻗어준 적이 있는 것도 같다는... 기억이 잘 안나지만 말이예요.

slee0303의 이미지

C# 코드입니다.

다수의 점들을 선으로 연결하는 코드를 아래와 갈이 작성했는데,
.

Point[] P = new Point[100];

//Set the points
........

for (int n = 0; n < 100; n++)
{ g.DrawLine(pen, P[n], P[n+1]);}


엄청나게 느리더군요.
C++ 에서는 아무 문제가 없었는데 C# 자체가 느린가보다 라고 생각하고 있다가 코드를 바꾸어 보았습니다.

Point[] P = new Point[100];

//Set the points
........

g.DrawLines(pen, P);


다시 빨라졌습니다.
이전 코드와 속도차가 수십배 되더군요.

두 코드의 차이는 먼저 코드는 선을 그을 때마다 그래픽 하드웨어에 액세스하고 나중 코드는 한번에 액세스해서 한꺼번에 그린다는 차이인데 그로 인해 그리 큰 차이가 날까요?
하드웨어 액세스 시 생기는 .NET 의 오버헤드 때문이 아닐까 하는 생각이 듭니다만...

wodnrrns의 이미지

저역시 C#이용하는중에 픽셀값들을 이용해 마스크를 만드는 작업이었는데요. 후배녀석 시켜놨더니 한점씩 받아 검사해서 하고있더군요.
동영상처리라 초당 2프레임정도 나오더군요. -_-;
객체지향에서 있는함수를 불러다 쓸경우 생기는 자주일어나는 현상인것같습니다.(버그는 아니지만요)
접근시간 문제도있겠지만 기본적으로 루프 안에서 함수 호출은 문맥시간 자체만으로도 많은 오버해드를 만드는것 같습니다.
(이건 C나 C++에서도 그렇지요.) 자꾸 C언어의 포인터가 편하다고 느끼는건 제가 못따라가고있는거겠죠...?ㅠㅠ

slee0303의 이미지

문제는 알고 있는 함수만 가지고 삽질을 하고 있는 제자신에게 있는 것 같아요.

꾸준히 배우는 자세로 일해야 하겠죠?

winner의 이미지

커널영역과 유저영역 왔다갔다하면서 생기는 오버헤드를 걱정했을 것 같은데 말이죠. ^_^

meteors의 이미지

C++에서 GDI로 프로그래밍 해도 마찬가지입니다.
메모리와 CPU 사이에서만 계산하는 것하고 비디오 카드에 액세스하는 것은 하늘과 땅만큼 차이가 납니다.

예를 들어 화면재생빈도가 60Hz라고 하면 1초에 60번 화면이 바뀐다는 것인데..
한 화면을 보이는데 약 1/60초가 걸린다는 뜻이죠.

그런데 윈도우즈가 다른 일을 하나도 안해서 모아서 그리지 않고
선 하나 그릴 때 1번씩 화면이 바뀌었다면 60개의 선을 그리는 경우 1초가 걸리고
모아서 그리면 1/60초가 걸리겠죠. 그럼 60배의 차이가 납니다.
실제는 CPU가 딴짓을 하느라 모아서 그리는 경우가 더 많기 때문에 60배까지는 차이가 안나겠지만요.

그래서 예전에 실제 사용하는 경우에는 double buffering 같은 기술을 썼습니다.
메모리에 한 화면 만큼의 공간을 잡아놓고 다 그린 다음에 그 화면만 비디오 카드로 보내고..
그 사이에 다른 메모리 공간을 잡아 다른 화면을 그리고 그 다음에 메모리를 바꿔치기 하고..

요즘에야 비디오 카드의 3D 기능이 발달해서 GDI는 안쓰겠지만요.

mithrandir의 이미지

최근에 wipi-c플랫폼에서 개발할 일이 생겼는데, 결과 어플을 폰에 올리고 실행하려고 하면
'컨텐츠를 실행할 수 없습니다' 란 메시지만 나오고 가타부타 이유가 없는거에요.

가끔은 다운로드 게이지가 다 올라가고 멈춰버릴때도 있고요. 이게 특정 object를 링크했을때만 생기는 문제였는데,
짐작가는 거라고는 object의 크기가 약간 큰(50kb정도)것 때문이 아닐까 하는거였어요.

그리고 결론부터 얘기하자면,

2MB가 넘는 global array 선언 때문이었지요.

#define CODE_SIZE (65536 * 20)

int code_buffer[CODE_SIZE];
...

저런 전역변수 배열이 여러개가 있었거든요.

전문가에게 물어보니 전역변수로 선언가능한 제한이 대략 7MB정도 된다고 하는데, (자질구례한거 합치면 8MB정도일까요?)

기존에 메모리 pool용으로 사용하던 정적변수도 몇MB있고 해서 그 제한에 걸려버렸나봅니다.
그래도 그렇게 시간이 걸릴 버그는 아니었는데,
디버깅 환경을 제공해주지 않았기 때문에 한번 컴파일->실행하는데 대략 30초가 넘게 걸렸습니다. 그것도 컴파일을 눌러놓고 업로드까지 자동으로 한 후,
폰을 꾹꾹 눌러서 다운로드를 받아줘야 했지요.

아마 jtag같은 디버깅 인터페이스가 있었다면 좀 쉽게 할 수 있지 않았을까 합니다.

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

서지원의 이미지

보통은 (embedded가 아닌 경우) uninitialize 된 변수들은 .bss segment에 (압축되어서) 저장되고 나중에 loader가 loading하면서 실제로 사용하는 만큼의 memory를 할당하게 되는데 embedded 환경의 경우는 아닐수도 있는가보네요.
(보통의 경우에는 object 의 크기는 uninitialize된 변수랑은 별로 관계가 없거든요...)

아니면 실제로 실행할 때에 에러가 난건가요?

mithrandir의 이미지

WIPI-C 어플리케이션이 segfault라도 내면 (예를들면 int *a=0x00, b=*a;) 따위의 짓을 하면
freeze되거나 혹은 폰이 재부팅되는걸 보면, OS라고 해놓고 exception처리도 제대로 안하는게 분명합니다.

.bss는 처리한다고 하더라도, paging을 안하는게 분명해요. -_-;;

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

angpang27의 이미지

audit buffer 이거 풀되면 시스템 행걸리드라고요.
국민통신사 서버 4개 다운시킨적이 있죠. 그 유명한..ICIS라고 하는..

고통이 지천에 있다한들 어이해 멈출수있더냐

wodnrrns의 이미지

부끄럽지만 저는 학생인데다가 교수님께서 윈도우를 좋아하시는 않좋은 환경때문에 MFC로 코딩을 자주하게되는데요
후배학생들 시켜놓으면 코딩은 좀 할수 있을것 같다는녀석들이 동적할당과 해제시에 C와 C++문법을 혼용해서 쓰더군요.
MSDN에는 안된다고 하지않고 장담하지 않는다고만 나와있는데, 디버깅시에도 정확하게 어디서 죽는지 나오는것도아니고
메모리 자체가 깨지거나 포인터가 안드로메다를 찍고있는 현상을 몇번 본적있습니다.
이건 좀 정적으로 안되게 하는게 옳은것 같은데 혼용해서 쓰면 안된다는게아니라 장담할수 없다니...
표준의 중요성을 다시한번 실감하게됩니다

likimda의 이미지

워낙 유명한 거지만.. 제대로 삽질해본 경험이 있어서 적어봅니다.

C언어에서.

int falg = 0;
 
// do something;
 
if(flag = 1)
{
  // error..
}

왜 항상 에러가 나는지 이해 못했습니다.
지금봐도 저런 실수를 어떻게 모르고 지나가나 싶지만..
막상 눈앞에 펼쳐지면 절대 눈에 안들어 오더군요.

지금은 습관적으로 상수를 앞에 두려고 노력합니다...

-----
Know yourself - Temple of Apollo, Delphi

-----
Know yourself - Temple of Apollo, Delphi

therealjoker의 이미지

상수를 앞에 쓰면 확실히 syntex error 로 미리 방지할 수 있겠군요 ^^

ceraduenn의 이미지

Joel On Software에서도 상수를 앞에 두는 습관이 좋다고 했었죠.

Summa Cum Laude http://ceraduenn.egloos.com

NoBrain의 이미지

전 어떤 책에서 보고 상수를 앞에 뒀다가 상사한테 혼났습니다.
자기가 보기에 맘에 안 든다구요.

그 땐 문법 에러보다는 가독성을 높이기 위해 그런가 했는데 좋은거 배워갑니다.

imyejin의 이미지

서로 되돌면서 끝나지 않게 정의된 디폴트 메서드 정의 때문에 가끔 애를 먹은 적이 있었습니다.

하스켈 표준라이브러리에 있는 같기 클래스(Eq)의 경우 디폴트 메서드 정의를 일부러 (==)을 (/=)의 부정으로 (/=)은 (==)의 부정으로 정의해 놓아 둘 중 하나만 정의하면 자동으로 나머지도 정의되게 하고 있습니다. 이게 편리하긴 한데요, 문제는 이걸 정의하지 않으면 경고는 나는데 컴파일 에러는 안나거든요. 그래서 한번은 새로운 데이타 타입 정의한 다음 같기 클래스 인스턴스를 일단 선언한 다음에 같기 연산자를 나중에 정의해야지 하고 아무것도 클래스 인스턴스에 정의 안해 놓고 다른 파일 작업하다 깜빡 정신을 놓고 이제 다 됐다 하고 컴파일하니까 컴파일 되네 어라 그런데 왜 돌다 무한루프 걸리지??? 이러고 한참 헤멘 적이 있습니다.

@ 컴파일러가 경고를 자세히 봅시다 -.-;; 나중에 정의할 거면 최소한 undefined 로 해놓읍시다.

임예진 팬클럽 ♡예진아씨♡ http://cafe.daum.net/imyejin

[예진아씨 피카사 웹앨범] 임예진 팬클럽 ♡예진아씨♡ http://cafe.daum.net/imyejin

Scarecrow의 이미지

struct나 class를 선언하고 괄호를 닫으면서 세미콜론 안쓰기...
for나 while문을 쓰면서 괄호열기전에 세미콜론 찍기...

같은 실수를 초보자들이 잘 하면서도 잘 못찾더군요.

blkstorm의 이미지

이것 때문에 여름학기 C++ 과목 텀프로젝트 밤샘했었죠. ㅠ.ㅠ

bushi의 이미지

예전(gcc4.0무렵)에 arm 부트로더 작업하다 겪은 ...

int a = 0 처럼 초기화 된 변수는 '무조건' .data 에 들어갈 것이라 가정하고 작성했는데,
'0 으로 초기화되는 것'들만 골라서 .bss 에 집어넣어 버리더군요.
부트로더가 타겟에서 돌 시점의 RAM 은... 그야말로 쓰레기장이라 뭐가 있어도 이상할게 없으니 제대로 돌 리가 없죠.
GNU 홈피의 gcc 매뉴얼을 뒤진 끝에 (운 좋게도) 결국 컴파일 옵션을 찾아내어 해결했었습니다.
(-fno-zero-initialized-in-bss)

놓치거나 오해하는 feature 때문에 스스로 감지하기 어려운 bug를 만들어내는 경우가 대부분이라 생각해서
글에 좀 어울리지 않는 댓글 달았습니다.
(실제론 feature 인데 bug 로 승화시킨 자신을 반성하자는 의미에서...)

OTL

dragonkun의 이미지

자바에서..

public void someMethod(String name) {
  if(name == "Linus") {
    // 어쩌구..
  }
}

또 다음 이야기들은 프로그래밍 버그라고 할 순 없는 실수들이지만...
친구 코드를 봐주는데 println 을 printIn 이라고 쓰면서 l(소문자 엘)과 I(대문자 아이)가 구분이 되지 않는 폰트를 써서..
컴파일 에러가 나는 걸 결국 해결 못해주고 나중에서야 깨달았던 적이 있었죠.

그리고 http://blog.naver.com/deregulation/50033736542 이 포스트도 참 인상깊었었죠..
--
Emerging the World!

Emerging the World!

lovian의 이미지

posix 기반으로 만들어 있어서 aix 32/64 hp 32/64 hp-ia 32/64
solaris 32 solaris-x86 32
에서 잘 작동하던 c 코드가 있었습니다.

마침 solaris 64비트 포팅 할 필요가 있어서, 작업을 했는데.
빌드에는 별 문제가 보이지 않았습니다.

그런데 유독 프로그램이 실행하다가 core가 발생하는 거에요.
아무리 해도 잡히질 않아서, 하드코어하게 기본이 되는 함수들만 남기고 디버깅을 시작해봤지요.

나중에 보니..
모듈화 시켜둔 코드에서 implicity 하게 호출한 함수들 중에서 헤더파일에 선언이 없는 함수를 호출하면 문제가 발생한거였네요.

결국 모든 함수들에 대해서 선언이 없는 것들 채워주고 나서 정상적으로 작동을 확인했네요.

역시 컴파일시 경고란 에러로 보는게 낫다는 것을 채감했어요 ㅎㅎ

-----------------
한글을 사랑합니다.

-----------------
한글을 사랑합니다.

서지원의 이미지

Quote:

나중에 보니..
모듈화 시켜둔 코드에서 implicity 하게 호출한 함수들 중에서 헤더파일에 선언이 없는 함수를 호출하면 문제가 발생한거였네요.

왜 이게 문제가 되는건가요? (implicitly하게 호출했다는게 무슨 말인지 잘 모르겠네요;;;)
컴파일시 에러/경고 면 이해가 가는데 실행시에 문제가 발생했다는게 이해가 잘 안되서...

Quote:

역시 컴파일시 경고란 에러로 보는게 낫다는 것을 채감했어요 ㅎㅎ

혹시 그 이외의 경고도 많이 나와서 그냥 같이 무시하신건가요? (경고가 그거 하나면 그래도 빨리 봤을꺼 같은데...)

bushi의 이미지

lovian의 이미지

해당 함수의 원형을 가지고 있는 헤더파일을 include하지 않은 상태로 또는 헤더파일에 없는 함수를 호출하는 코드를
빌드를 하게 되면, 컴파일시에 경고가 뜨죠. (함수 원형을 모르는 상태에서, 함수를 호출하는 것이 암묵적인 호출이죠)

링킹시에는 올바른 object가 있으므로 별 문제가 발생하지 않거든요.

설명 드렸던 데로 왠만한 플랫폼에서는 문제가 발생하지 않았습니다. :)

경고를 무시했던 이유라면, 이미 많이 테스트된 소스코드라서 상당히 신뢰하고 있었기에,
별다른 의심을 하지 않았던거였죠.

실행시 발생했던 segmentaion fault의 정확한 이유는 아직도 모르고 있네요 ..
-----------------
한글을 사랑합니다.

-----------------
한글을 사랑합니다.

seethewind의 이미지

저는 뭐 MFC 개발자인데 최근에 프로젝트가 산업현장에서 어떤 장비를 컨트롤하는
터치 프로그램(일반적으로 현장에서 터치라고 부르는) 을 PC 로 포팅하는 프로젝트였습니다.
산업현장에서 터치는 별도의 개발툴이 있고 터치 스크린 하드웨어도 따로 있죠

그런데 이게 PC 포팅하고나니 어느순간 프로그램이 띠띡 거리면서 죽더군요
나중에 원인을 찾아보니 GDI 객체가 10000 개가 넘으면 프로그램이 죽는다는걸 알고는(xp 기준)
처음에 만들었다 안쓰는 컨트롤들은 다 숨겼는데 그 숨긴거 다 찾아서 없앤다고
고생좀 했습니다. 겨우 겨우 8000 개정도로 맞춰서 돌렸네요

그나저나 참 이사람들도 이런걸 왜 PC 로 포팅하자고 했는지가 무지 궁금합니다.
하여튼 지나치게 컨트롤도 많고 이쁘게 해달라고 해서 아이콘도 엄청 올리고 폰트도 막 만들고
에휴...

바람을 눈으로 보다 SeeTheWind

바람을 눈으로 보다 SeeTheWind

서지원의 이미지

Quote:

나중에 원인을 찾아보니 GDI 객체가 10000 개가 넘으면 프로그램이 죽는다는걸 알고는(xp 기준)
처음에 만들었다 안쓰는 컨트롤들은 다 숨겼는데 그 숨긴거 다 찾아서 없앤다고
고생좀 했습니다. 겨우 겨우 8000 개정도로 맞춰서 돌렸네요

왜 객체가 10000개가 넘으면 프로그램이 죽었는지 혹시 기억 나세요? (메모리를 많이 써서 그럴 것 같긴 한데...)
GDI객체가 10000개가 넘는게 문제인걸 어떻게 알아내셨나요?

grassman의 이미지

http://msdn.microsoft.com/en-us/library/ms724291(VS.85).aspx

Windows XP의 경우 프로세스당 GDI 객체는 총 10000개가 기본값이라고 되어 있네요.
레지스트리 값을 수정하면 65535개까지 지정할 수 있다고 합니다.

seethewind의 이미지

프로그램 돌려놓고 작업관리자 띄워놓고 아무리 봐도 메모리는 아니길래
열선택해서 프로세스별로 이것저것 다 띄워놓고 보니 그러던데요...

생각해보니 GDI 문제는 예전에 아이콘 많은 프로그램에서 한번 delete icon 을 안해서 겪은적이
있기도 하고요...

레지스트리에서 늘릴수는 있다고 하지만 구글에서 찾아보니 용기가 있으면 시도하거라~

라고 말씀해주시길래... 줄이는 방향으로 했습니다.

아 그래고 10000 개 넘으면 프로그램이 죽는다기 보다는 더이상 GDI object 를 생성을 못해요

바람을 눈으로 보다 SeeTheWind

바람을 눈으로 보다 SeeTheWind

서지원의 이미지

네. 여기서는 stackoverflow의 글타래보다 좀더 구체적으로 (이왕이면 코드 예시와 함께....) 토론해서 좀더 건설적인 글타래가 되었으면 하네요...
(stackoverflow에도 괜찮은 답변들이 좀 있긴 하지만...)

mirr187의 이미지

최근에 진행중인 프로젝트에서 multi-thread로 개발중인데 매번 죽는 위치가 달라서 고생꽤나 했습니다...
원인을 찾기 위해서 호출되는 function들을 잘개 쪼개어서 테스트해보니.. encode를 하는 부분에서 초기화가 누락된게 원인이더군요.. -_-;;
malloc하고 memset하는 부분이 누락되어 메모리 참조시 문제가 발생했었습니다.. 그래서 calloc을 주로 써왔는데.. 다른 분이 개발한 것을 토대로 하다 보니 또다시 이런 문제가 생기더군요... OTL...

서지원의 이미지

valgrind를 썼으면 혹시 좀더 빨리 찾을 수 있었을까요?

mirr187의 이미지

다음과 같은 코드가 있다고 했을 경우...

#include
#include
#include

int main()
{
char *tmp = malloc(10);

strcpy(tmp, "hello");
free(tmp);
}

제가 아는 옵션이 몇개 없어서 그런지.. 안 나오더군요.... ;;; 혹시 아시는 분은 제보 바랍니다.. -_-;;

jick의 이미지

...에러가 나야 하는 코드인가요?

bushi의 이미지

strcpy() 말고 strcat() 이면 그럴싸하죠.
이런 걸 찾으려면 http://kldp.org/node/94098 가 도움이 되겠지만,
재수없으면 이마저도 무용지물일 수 있습니다.

OTL

NoBrain의 이미지

저도 이상하게 이해가 안 가네요.
직접 만들어서 돌려봤는데..
잘되는데..

strcat은 당근;;

bookworm의 이미지

C 언어로 간단한 프로그램을 만들던 시절이었는데요.
컴파일러는 당연히 볼랜드 C++ 1.0.

#include <stdio.h>

컴파일만 시키면 이 첫줄에서 신택스 에러를 뿜더군요. 정말 한참을 삽질했습니다.

솔직히 너무 말이 안 되는 에러니까요. 런타임도 아니고 컴파일 타임에러라니...

나중에 원인을 보니 컴파일러가 볼랜드 C++가 아니라 볼랜드 파스칼이더군요. ㅡㅡ;

당시 파스칼과 C를 왔다갔다 하면서 개발을 하던 때라....

--

B/o/o/k/w/o/r/m/

B/o/o/k/w/o/r/m/

bxhs의 이미지

activex 를 만들때, 자바스크립트 연동을 위해서 이벤트를 만듭니다.
액티브X의 주 쓰레드와 거기서 사용하는 다른 쓰레드가 있을때,
다른 쓰레드 에서 발생시키는 이벤트는 웹상에서 전달되지 않습니다.
웹환경의 특수함(익스플로어만..??) 을 경험한 순간이었습니다..
응용프로그램에서 activex 를 불러 쓸때는 아무 상관 없더군요.
돌이켜보면, 잡기 힘든 버그의 80%이상이 쓰레드간에 발생되는 일들인듯하네요
최악의 경우는, 어떤 라이브러리내의 함수를 호출하는데,
이런 때는, c/c++의 원칙을 까먹기 쉽상입니다.
이런때, 쓰레드와 포인터가 연관되어 일어나는 버그는.....
하루 이틀 고생해야 발견하는듯 합니다.
물론, 컴파일러가 너무 좋아져서, 점점 단축되기는 하지만..

NoBrain의 이미지

fopen("/tmp/test.txt", "W");

""사이에 대문자 W가 있습니다. 학창시절 친구가 이상하다고 해서 한참을 봤는데 못 찾겠더라구요.
오류가 런타임 시에만 나는 것입니다. VS 6.0이었는데 요즘은 어떤지 모르겠습니다.

폰트를 바꿔야겠죠?
휴... 이것도 어렵네요!!!

ddeng72의 이미지


if(abc == 123);
{
//do something
}