유닉스로 개발된 C 소스를 리눅스에서 컴파일만 하고서 돌리면 잘 돌아갈까? 대부분 프로그램들은 잘 돌아가지만 몇몇 코드들은 손을 봐줘야 하는 것들이 있다.
그중에서 함수로 아규먼트를 넘길 때 문자열 이슈가 있다. 특히 readonly 문자열 값을 아규먼트로 넘길 때 끝처리에서 다르게 동작한다.
001: void function_test_str( char *str ) {
002: char tmp_str[100];
003: size_t len;
004:
005: len = strlen(str);
006: strncpy( tmp_str, str, sizeof(tmp_str));
007: tmp_str[len] = 0x00; /* 확실한 막음처리 */
008: printf("len=[%u] str=[%s] tmp_str=[%s]", len, str, tmp_str );
009:
010: str[len] = 0x00;
011: };
이라고 선언된 함수가 있다고 하면 이 함수에서 str 을 조작할 때 예기치 않은 문제가 있을 수 있다.
이 함수를 다음과 같이 호출했을 때 리눅스에서는 아래와 같이 결과가 나오면서 코어덤프가 발생된다. 문제의 라인은 10 라인이다.
호출 : function_test_str("abc");
결과출력 : len=[3] str=[abc] tmp_str=[abc]
쌍따옴표로 감싼 문자열을 바로 전달할 때 NULL문자로 막음처리가 되어 전달은 된다. 그렇다고 그 뒤에 붙어 있는 NULL문자는 abc 문자열의 일부라고 볼 수 없다. 리눅스에서는 0 번지의 포인터에 값을 쓰게 되면 코어덤프가 발생된다. str변수의 4번째 위치는 금단의 영역이다.
str[3] = 0x00;
보통의 경우 str 의 마지막에 한글자 여유공간이 있겠지만 리눅스의 경우 참 까탈스럽게도 문자열 마지막 끝의 번지에 잘못 건드리면 죽는다. 건드리면 역린 죄로 SIGEGV 를 받게 된다.
SIGEGV는 세그멘테이션 오류 (segmentation fault)라고 알려진 signal 11 오류이며 프로그램이 할당되지 않은 메모리에 접근한 경우 발생하는 오류이다.
안전한 방법으로는 별도의 지역변수를 선언하고 거기에 값을 복사해서 사용하는 것을 권장한다.
char tmp_str[100];
strncpy( tmp_str, str, sizeof(tmp_str));
tmp_str[strlen(str)] = 0x00; /* 확실한 막음처리 */
보통의 경우는 strncpy하면 NULL 막음 처리 되어 잘 복사된다. 하지만 어떤 경우에는 tmp_str 에 NULL 문자로 막음 처리가 안 된 경우도 볼 수 있다. 이것은 아규먼트로 넘겨받은 str 이 NULL로 막음처리가 되어 있기는 일반적으로 우리가 하는 0x00 문자는 아니다. 그래서 strncpy 한 후에 다시 확실한 막음처리를 추가로 해주는 것이 안전하다.
'컴퓨터활용 > 리눅스' 카테고리의 다른 글
리눅스 디렉토리 사용량 (0) | 2020.06.16 |
---|---|
U2L프로젝트 ltoa 이슈 (0) | 2020.05.26 |
U2L프로젝트 printf 이슈 (0) | 2020.05.19 |
U2L 프로젝트 fclose() 이슈 (0) | 2020.05.19 |
티맥스 서버가 수행중 죽을 때 (0) | 2019.11.07 |