과제간단해설및소개 정우영조교 최종업데이트 : 2013-12-14
들어가며 이거자체는 1 번과제끝나고부터만들기시작했는데어쩌다보니배포는이제와서야 ㅜㅜ 대략적인문제만집었습니다. 프기실 에해당하는문제는가능한집지않으려합니다. 앞으로추가할거있으면하겠지만.. 이제마지막이네요ㅡㅡ ;
sizeof 연산자 array, struct/union 에대해선할당받은크기 포인터에겐포인터의크기를돌려줌 array 를어떤함수에게넘기면, 해당함수안에선, 포인터로접근하기때문에크기를모름. 어떤포인터가가리키고있는메모리의크기를알수있는방법은없음
int a; int b[5]; int *c = malloc(5 * sizeof(int)); struct st1 { char c[18]; }; union un1 { char c[14]; int i[5]; }; struct st1 d; struct st1 e[2]; union un1 f; union un1 *g = malloc(3 * sizeof(union un1)); sizeof a : 4 sizeof b : 20 sizeof c : 8 (on 64-bit) sizeof d : 18 sizeof e : 36 sizeof f : 20 sizeof g : 8 sizeof pointer of array : 8 printf("sizeof a : %ld\n", sizeof a); printf("sizeof b : %ld\n", sizeof b); long size(int *b) printf("sizeof c : %ld\n", sizeof c); { printf("sizeof d : %ld\n", sizeof d); return sizeof b; printf("sizeof e : %ld\n", sizeof e); } printf("sizeof f : %ld\n", sizeof f); printf("sizeof g : %ld\n", sizeof g); printf("sizeof pointer of array : %ld\n", size(b));
sizeof 연산자 문자열의크기를알아내기위해선, sizeof 가아닌 strlen 을사용해야함. char h[16] = "hello?"; char *i = "hello?"; printf("sizeof h : %ld\n", sizeof h); printf("sizeof i : %ld\n", sizeof i); printf("strlen h : %ld\n", strlen(h)); printf("strlen i : %ld\n", strlen(i)); sizeof h : 16 sizeof i : 8 strlen h : 6 strlen i : 6
무모한 pointer dereferencing if (input_url[7] == / ) 이행동을하기전에우선 input_url 의크기가 7 보다큰가확인합시다. strlen 구현은딸랑 5 줄이면 ok. size_t strlen(const char *str) { size_t size = 0; while(str[size++]); return size - 1; }
if 남발 if( input_url[0]!= 'f') if( input_url[1]!= 'i') if( input_url[2]!= 'l') if( input_url[3]!= 'e') ( 이렇게 15번비교 ) 많이비효율적이긴하지만, 윗사례보단차라리나음. 안전하기때문에. 그래도이러진맙시다...
우리에겐 strncmp 가있다. http://www.cplusplus.com/strncmp 직접구현하는것도간단 33 int strncmp(const char *a, const char *b, size_t size) 34 { 35 for (size_t i=0; i<size; i++) 36 { 37 if (a[i] > b[i]) 38 return -1; 39 else if (a[i] < b[i]) 40 return 1; 41 } 42 return 0; 43 }
getenv 조작 getenv 로받은주소의데이터를덮어씀 28 char *str = copy me! ; 29 char *home = getenv("home"); 30 strcat(home, str); 기존시스템의환경변수가날아감
getenv 조작 간단한확인코드 결과 덮어쓰는코드로 잠재적인위협 28 char *home = getenv("home"); 29 30 // look at the starting point and the ending point 31 for (int i=-200; i<200; i++) 32 putchar(home[i]); s:/usr/bin/eclipse:/usr/bin:/home/minsl/pintos/src/utilslc_identification=ko_kr.utf- 영향받는부분 8PWD=/home/minsl/testJAVA_HOME=/usr/lib/jvm/jdk1.6.0_35LANG=en_US.UTF- 8LC_MEASUREMENT=ko_KR.UTF- 8SHLVL=1HOME=/home/minslLANGUAGE=enLOGNAME=minslSSH_CONNECTION=115.125.135.131 8253 115.125.135.131 29LESSOPEN= /usr/bin/lesspipe %sxdg_runtime_dir=/run/user/minsldisplay=localhost:11.0lessclose=/usr/bin/l 이렇게문제터지면디버깅도힘들다
getenv 조작 제안 : 버퍼를새로만들어받아옵시다. char buffer[1024]; strcpy(buffer, getenv("home")); strcat(buffer, str); ( 물론 getenv("home") 접근이안전하다고가정함 )
1 byte I/O 1 byte 로 sys_read/sys_write 호출 char c; read(fd1, &c, 1); write(fd2, &c, 1); 만약 PA 1 에서운좋게 pass 됐어도, PA 2 에선 long time 을받았을것임. 매우느립니다. 따라서, 적당히큰버퍼를잡아서사용합시다. 권장 : 4K~128K (4,096 ~ 131,072 bytes)
Define 한값을사용합시다. 사례 : if (errno == 2) // 2 == ENOENT { return -1; // #define ERR_NO_FILE (-1) } 과제를만든사람들도 -1-2 -3-4 가무엇을의미하는지기억하지않습니다. 마찬가지로에러번호대신에 ENOENT 같은이름을씁니다. 다음과같이하세요. return ERR_INVAL_URL;
쓰지않을파일은열지도말라 사용하지않을파일을만들고보는경우. int fdout = open(output_path, O_CREAT O_RDWR, ) // returns true if input_url is valid if ( url_validate(input_url) == false) return ERR_INVALID_URL; URL 검사를하지않고쓸파일부터만들고보는경우혹은읽을파일이열리지않지만쓸파일부터열고보는경우 만약 O_TRUNC flag 가붙어있으면지우면안되는멀쩡한파일을하나날릴지도모름.
자원을해제할때 최근문제가된코드를보면, double free 를시도하던가 close(0) 을시도한코드가많음 // main thread int *connfd = malloc(4); *connfd = accept(); pthread_create(..., th_main, connfd); free(connfd); // double free th_main(void *arg) { int cfd = *(int *)arg; free(arg); // double free } thread 사이에선 address space 공유!
자원을해제할때 close(0); 문제예시 : void *thread_main(void *arg) { int fd; gcc 는 0 으로초기화. (vs 에선 0xcccc.) // 매우복잡한코드, // 하지만 fd 는사용하지않을 수 있음 } close(connfd); close(fd); closing FD 0 return NULL; 더이상표준입력 (stdin) 에서입력을받지못함 새로운 ( 파일 ) 디스크립터가 0 번으로열림
자원을해제할때 close(0); // 더나쁜예시 : time main thread creates children threads initial FD FD 0 (stdin) FD 1 (stdout) FD 2 (stderr) child 1 child 2 child 3 thread 종료전 close(0); 발생 FD 0 (closed) FD 1 (stdout) FD 2 (stderr) FD 3 (closed) main s accept() 0 [socket] FD 0 (socket) FD 1 (stdout) FD 2 (stderr) FD 3 (file) (0 closed by child 3) FD 0 (closed) [socket] FD 1 (stdout) FD 2 (stderr) FD 3 (file) close(0); 발생 FD 0 (closed) [child 2 s fd] FD 1 (stdout) FD 2 (stderr) FD 3 (don t care) FD 4 (closed) [socket] 해당소켓으로가는모든통신이막힘 : PA 5 long time 원인의하나
자원을해제할때 : 변수초기값 쓰레드를사용할땐, 주소공간을공유함을주의. 이런불상사를방지하기위해, 변수를다음처럼선언할수있음. int fd = -1; (file operation 에서 fd 가 -1 일경우아무일도안함 ; 최소한예측불가능한사태가일어나진않음 ) 이건한예방책이고, 이런문제가애초에발생하지않도록코드를작성할것. ( 모든경로에대해자원사용여부를확인하세요 )