이사람아 1줄의 코드가 천년을 결정하는겨

6074
points
points
얼마전에 겪은 버그죠
http://kldp.org/node/97603 와 http://my.oops.org/74 를 보시면 아시겠지만
python 2.3 에서 \t\n 으로 잘못 코딩하는 바람에 엄한데서 아직까지 괴로움을 겪었습니다.
정말 1줄의 코드라도 소중하게 커밋하고 배포시에 테스트를 열심히 하여야 겠습니다.
장인정신이 필요한 시점입니다.
여러분이 겪은 경우가 있다면 이야기 해주세요 ^-^
»
- 다즐링의 블로그
- 인쇄에 적합한 버전
- Login or register to post comments
- 5476번 읽힘

points
예전에 ...
잠깐 젠투를 썼었을 때..
stage3 에서 시작해서 다 깔고 며칠에 걸려서 emerge ... 로 몇개 마스크 걸린 것 빼곤 다 최근 update 까지 바꿔놓은 다음에 stage3 압축 파일을 지우려고 ..
rm -rf /stage3 까지 치고 탭키를 눌러서 지우고 .. 이렇게 한다는 것을.
rm -rf / stage3 탭 이리 되었습니다.
.... 뭐 뒤는 말할 필요가 없을 듯 .. 합니다.
딱 하나의 차이인데 ... 며칠간의 작업이 훨훨 ....
---------
귓가에 햇살을 받으며 석양까지 행복한 여행을...
웃으며 떠나갔던 것처럼 미소를 띠고 돌아와 마침내 평안하기를...
- 엘프의 인사, 드래곤 라자, 이영도
즐겁게 놀아보자.
http://akpil.egloos.com
points
예전에 게임을 만드는 회사에서 일을 했는데
어느 순간부터 화면이 미친듯이 떨리더군요. 약간 FPS같은 어드벤쳐 게임이었는데, 화면이 떨리는 증상 때문에 다들 며칠씩 고생을 했습니다.
한 일주일 만에 원인을 찾았습니다. dx랑 충돌나서 그런가 해서 dx도 갈아없고, 아무튼 손을 안댄 곳이 없었는데
원인은 참 어처구니 없었습니다. 주인공 시점을 움직이고 계산하는 코드가 for문으로 짜여져 있었는데, 비교와 증가가 0.1 단위로 되어 있더군요.
아시다시피 CPU에서 0.1 표현이 안되죠. 그러니 증가 후 비교하는 과정에서 우리가 생각하는 것 처럼 딱 값이 떨어지지 않기 때문에 계속 값이 변하고, 그래서 화면이 흔들렸던 거였죠.
뭐 그래서 1 단위로 증가하고 비교하고 실제 값은 거기에 10을 나눠서 했습니다.
points
0.1 곱하기 100은 9.99입니다^^
학교에서는 0.1 X 100 = 10이라고 가르치죠?
부동 소수점방식에서는 0.1 X 100 = 9.99입니다^^
덤으로
#include <stdio.h> int main(void) { float y = 1e11F; printf("Your balance is %.2f\n", y); return 0; }위 코드의 결과값은 99999997952.00입니다. 무려 2048이라는 엄청난 오차가 났군요.
컴퓨터를 믿느니 차라리 제 연필을 믿고 말겠습니다-ㅅ- (물론 이건 농담입니다.)
---
“내게 능력주시는 자 안에서 내가 모든 것을 할 수 있느니라.”(빌립보서 4:13)
points
1e10F 은 컴퓨터와 연필이 같은 답을 내놓는건 왜 인가요??
아래와 같이 만들었더니..
#include "stdafx.h"
#include
int _tmain(int argc, _TCHAR* argv[])
{
float y = 1e10F;
printf("1e11F is %.2f\n", y);
unsigned int t1 = 1;
float t2 = 1.0F;
for(int i=0; i<10; i++)
{
t1*=10;
t2*=10.0;
}
printf("int 1*10^10 is %d\n", t1);
printf("float 1*10^10 is %.2f\n", t2);
return 0;
}
결과값은...
1e11F is 10000000000.00
int 1*10^10 is 1410065408
float 1*10^10 is 10000000000.00
points
일단 이럴 땐 int의
일단 이럴 땐 int의 범위(4.3e9 정도 됩니다)를 넘어서므로 int로는 제대로 안 나올 테고,
float는 10^10까지는 정수를 저장할 때만 큰 문제가 없습니다. double은 10^14까지.
points
C교재 연습문제에서도 본 기억이...
학부 다닐 때 "A Book on C"교재로 C수업을 들었는데, 연습문제중에
비슷한 예가 있었습니다. 부동소수점 비교(출력?)에 한 예제였는데,
지금 다시 찾아보려니깐 못찾겠네요.
그 당시에는 정말 이해를 못했는데...
points
미국 장거리 전화망 다운 사태
1990년 1월, 미국의 장거리 전화망이 9시간동안 다운되어 60만명이 시외통화를 못하는 일이 벌어졌습니다.
신뢰성의 상징인 전화망이 왜 다운이 되었을지에 대해 추측이 난무했고 "해커들이 저질렀다"라는 불안이 싹트게 됐죠. 이로 인해 일부 애꿎은(?) script kiddy들이 억울하게 기소가 되기도 했고 실제 해킹과는 전혀 무관한 GURPS Cyberpunk라는 TRPG 룰북을 발행하던 출판사는 경찰에 털려 모든 컴퓨터를 압수당하기도 했습니다. 이 사건을 계기로 사이버스페이스 인권단체인 Electronic Frontier Foundation가 설립되기도 했습니다.
그러면 전화망이 다운되었던 원인은..? Bruce Sterling의 The Hacker Crackdown을 인용해보겠습니다.
해커같은 것이 원인이 아니라 AT&T에서 괄호 처리를 잘못해서..
points
ㅎㅎㅎ 실제 있었던
ㅎㅎㅎ 실제 있었던 일인가요? 브루스 스털링이 작가라 왠지 인용하셨다는 글도 소설의 일부분 같네요. ^^
--->
데비안 & 우분투로 대동단결!
points
넌픽션
넌픽션도 쓰셨습니다. 전부 사실입니다.
http://www.gutenberg.org/etext/101
여기서 읽어보실 수 있습니다.
points
인용하신 내용중에서
if에 딸린 break문은 원래 do...while을 빠져나가려고 한건데 if가 switch문에 있어서 의도와는 다르게 switch문을 벗어난거라고 해석했습니다
간단하게 예를 들면
int i = 0, j = 0; do { switch (i) { case 0: if (j == 0) dosomething(); break; /* 내 생각 : 루프를 빠져나갈꺼야 */ } } while (1);무한 루프 돕니다. if에 딸린 문장은 dosomething(); 하나뿐이고 break는 switch문에 포함되니까요.
그렇다고 dosomething(); 이 줄을 삭제하면 되느냐? 아니죠. break는 if문에 메이지만 여전히 switch문만 빠져나갑니다.
제가 해석한 것이 맞다면 두가지 모두 괄호로는 해결이 안되지요.
int i = 0, j = 0; do { switch (i) { case 0: if (j == 0) { /* 괄호 추가 */ dosomething(); break; /* 내 생각 : 루프를 빠져나갈꺼야 */ } } } while (1);dosomething(), break모두 if에 메이지만 break는 switch만 빠져나가 무한 루프돕니다.
제가 생각하고 있는게 맞나요?
points
그렇다면 제
그렇다면 제 실수입니다.. 6^^;;
points
포트란 오류로 우주선이 떨어졌다는 이야기가 생각나는군요. ^^;
대학교때 교수님한테 들었던 이야기 같은데...
다시 찾아보니 마소에 해당 내용이 실렸던 적이 있는듯 합니다.
http://www.imaso.co.kr/?doc=bbs/gnuboard_pdf.php&bo_table=article&page=1&wr_id=3538&publishdate=20031201
points
역사상 최악의
역사상 최악의 소프트웨어 버그
http://www.wired.com/software/coolapps/news/2005/11/69355
points
float형을 binary compare하려다가...
두 float array의 비교를 memcmp 한줄로 처리하려고 했었었습니다.
분명히 두 array는 모두 0.0으로 채워져 있음을 확인했는데도 불구하고 memcmp() != 0 이나와 확인하다보니...
0.0 != -0.0 이더군요.
그러니까
0.0 = 0x00000000 이고
-0.0 = 0x80000000 이다보니 memcmp로 binary comparison이 안되더라는 --;
어찌보면 당연한 문제를 편하게 코드를 짜려다가 삽질을 했었더랍니다.
열심히 살자
points
System 프로그래머의 비애
전 최근 이런 버그도 겪었습니다.
static int startPos = 0; if (startPos >= MAX_POS) { startPos = 0; } else { startPos++; } //startPos는 여러 쓰레드가 동시 접근 가능하므로 MAX_POS보다 클 수도 있다. //따라서 % 연산자로 보정해준다. int localPos = startPos % MAX_POS; myStructType *myStruct = &structures[localPos]; // -> 여기서 MAX_POS보다 큰 값이 들어와 엉뚱한 메모리 참조이 코드가 왜 서버를 비정상 종료시켰을까...
한참을 머리를 싸맸죠...
결론은...HP 장비의 컴파일러가 띠뚱한 옵티마이징을 한 이유였습니다.
즉 % 연산자가 atomic하게 이루어지는게 아닌게 문제였습니다.
컴파일 옵티마이징 단계에서 %의 연산자가 여러 연산자로 쪼개졌고,
%연산을 하는 과정에서 startPos의 값이 바뀌어
결과적으로 localPos가 MAX_POS를 넘어버리는 비정상적인 값을 가져왔죠...
에혀...
플랫폼별로 예상치 못하는 이런 결과를 종종 보게되는데...
시스템 프로그래밍을 하시는 분들 이런 경험들 없으세요??
points
분석을 잘 못 하신것
분석을 잘 못 하신것 같습니다.
( 애초에 % 연산은 대부분의 cpu 에서 2의 n 승과 % 를 하는 경우에 & 로 optimize 되는 케이스를 빼고는 나누기 연산과 크게 다르지 않습니다. 따라서 optimize 를 한다고 해도 여러연산자로 쪼개질 수 없습니다. 쪼개 졌다면 그 asm 코드를 올리셔야 할 것 같습니다만... )
( * MAX_POS 가 충분히 작아서 startPos 값의 overflow 가 없다고 가정하는게 우선 중요할 것 같습니다. 또한 startPos 값에 실수로라도 음수가 들어가지 않는다고 가정하겠습니다. )
그리고 말씀대로 설사 최적화가 일어나서 % 연산이 쪼개지고, 그 결과로 startPos 가 연산 도중에 바뀌는 경우가 있다 하더라도 MAX_POS 와의 % 연산 결과는 언제나 MAX_POS 보다 값이 작아져야 정상입니다. ( 연산 결과 자체는 여러 쓰레드를 하던 뭐하던 어차피 localPos 라는 stack 에 쌓이므로 중간에 바뀔 수는 없습니다. )
분석을 다시 해보시는게 좋겠습니다. 당장 문제가 사라졌다고 하더라도, 잘못된 분석에 의해 해결이 된 경우는 잠재적으로 문제가 생길 수 있습니다. ( 특히 시스템 프로그래밍은 그 문제가 잘 안보이다가 어느날 터지기도 하니까요... )
points
그렇다면...
저도 % 연산자가 어떻게 쪼개지는지까진 살펴보진 않았습니다.
그냥 그러지 않고서야 %연산결과가 왜 젯수인 MAX_POS와 같은 값이 나왔냐는 겁니다.
neogeo 님께선 왜 그런 결과가 나왔는지에 대해 어떻게 추측하시는지요?
참고로 컴파일러 옵티마이징 레벨을 낮추면 절대 발생하지 않습니다.
points
연산 중에 startPos 의
연산 중에 startPos 의 값이 변하는 것을 막으면 되겠죠.
startPos 가 여러 쓰레드에서 접근되는 자료라면 보호 해주세요.
% 가 아니라 + 연산이라도 예외없습니다.
컴파일러의 옵티마이징이 빚어낸 어처구니없는 결과도 아니고,
알면서도 실수한 코더의 민망함도 아닙니다.
OTL
points
위에 제가 적은
위에 제가 적은 가정대로 MAX_POS 가 얼마인진 모르지만 starPOS 가 overflow 가 날 수 있다는게 기본 가정입니다.
음수를 % 한 결과값을 집어 넣으려 하면 엉뚱한 결과가 튀어나올 수 있지요. 그렇게 되면 unsigned 입장에선 MAX_POS 보다 커보이는 값이 access 되거나 혹은 - 로 계산되더라도 없는 주소를 access 해버리게 됩니다.
그리고 정확히 MAX_POS 와 아예 같은 값이 나온것인건가요?
그렇다면 또다른 추측상으로는 localPos 에 대한 stack frame 이 깨져서 누군가 덮어썼다는 추측도 가능합니다.
각자 다른 thread가 call 한 함수내의 local 변수가 static 이 붙어있지 않는한 값이 변할리가 없을테니까요.
어디선가 메모리를 깨먹으면서 덮어쓰나 보시기바랍니다. 옵티마이즈 옵션에 따라 결과가 변하기 보단 혹시 디버그 모드와 일반 모드가 다른건 아닌지?
디버그모드는 예를 들어 메모리 공간을 앞뒤로 넉넉히 잡아주는 경우가 있기때문에 문제가 잘 안드러날 때도 있습니다.
MAX_POS 가 혹시 2^31 이런값은 아닌지.. ( sizeof(int) 가 4라는 가정하에 ) 2^31 - 1 로 잡아주셔야 정석이고, 사실 저 thread 가 여러군데서 접근하다보면 2^31 을 가지게 되고 그순간 음수로 돌아서버리는 수도 있으므로 주의하셔야합니다.
Neogeo - Future is Now.
points
저런경우는...;;
Mutex로 보호하지않은 것이 잘못이죠 ^^;
단순히 +1 하는 과정에서도 얼마든지 atomic하게 동작하지않을 가능성이 있습니다.
생각보다 많은 프로그래머들이 boolean flag 값만을 가지고 멀티스레드 동기화를 하려고 하는데...정확한 동기화는 이루어지지않지요 -ㅁ-;;;
물론!! 쓸데없는 동기화는 안하는게 최고죠 ㅎㅎ (그냥 대충~ 어느정도의 값만 필요하다던가, 그런경우가 있지요. 정확한 카운트가 필요없는.)
------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/