컴퓨터활용/유닉스

strcpy 의 위험성

멜번초이 2008. 9. 11. 13:43
반응형
strcpy 를 사용할 때 그 변수의 사이즈에 대하여 정확히 인지를 하고 사용해야 한다. 자칫 잘못하면 엄한 메모리의 영역까지 엎어칠 수 있다.

다음의 예제는 a 라는 스트링 변수에 문자를 2 byte만 넣을 수 있는데 이것을 오버하여 무턱대고 strcpy 를 했을 때 그 뒤에 바로 따라오는 변수 b의 기존 값(12345)이 뭉개져 버리는 것을 보여주고 있다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct a {
    char a[3];
    char b[10]; 
} a_t;
    
main() {
    a_t a;
   
    strcpy( a.b, "12345" );
    printf("b ptr=[%p] len=[%ld] size=[%ld] value=[%s]\n",  
              a.b, strlen(a.b), sizeof(a.b), a.b );
   
    strcpy( a.a, "123456789012345678" );
    printf("b ptr=[%p] len=[%ld] size=[%ld] value=[%s]\n",  
              a.b, strlen(a.b), sizeof(a.b), a.b );
};


출력 결과는 다음과 같이 원래 있는  b 변수의 값이 12345 였으나 a 변수에 사이즈 보다 큰 값을 strcpy 하는 순간 b변수 영역까지 엎어쳐서 b변수의 값이 변경되어 보인다.

b ptr=[0022FF63] len=[5]  size=[10] value=[12345]
b ptr=[0022FF63] len=[15] size=[10] value=[456789012345678]

b 변수의 값이 뭉개진 후에는 strlen(b) 한 값이 정상값 5가 15로 늘어나면서 sizeof(b) 한 10 보다 더 커져 버린 것까지 적나라하게 보여주고 있다.

이러한 문제를 해결하기 위하여 strncpy 를 사용하여 target 변수의 사이즈만큼만 strcpy 하는 것을 권장한다.

strncpy( a.a, "123456789012345678", sizeof(a.a) );

매번 프로그램에서 strncpy 를 사용하면서 뒤에 sizeof 해서 크기를 넣기가 귀찮다면 매크로로  wrapping 해서 사용할 수도 있다.

#define STRCPY(_dest, _src)                     \
    do {                                        \
        long        _isz;                       \
                                                \
        _isz = sizeof(_dest) - 1;               \
        if(_isz < 0)                            \
            _isz = 0;                           \
                                                \
        strncpy(_dest, _src, _isz);             \
        _dest [_isz] = (char) 0;                \
    } while(0)

여기서 굳이 do .. while 로 묶어 준 것은 STRCPY(a, b) 한 뒤에  세미콜론 (;) 문자를 기술하지 않으면 컴파일시에 오류가 나도록 하기 위함이다. 어느 문장은 세미콜론(;) 이 있고 어느 문장은 세미콜론(;) 이 없다면 혼란스러우니 일관성있게 모두 문장의 끝에는 세미콜론(;) 을 찍도록 표준화하기 위한 꼼수인 것이다.


strncpy 의 이해

그렇다면 strncpy를 사용할 때의 위험성은 없을까? 정확히 이해하지 못 하고 사용한다면 원하는 결과를 얻을 수 없기는 마찬가지이다.

strcpy( name, "최성환");
strncpy( name, "ab", 2 );


name을 출력해 보면  결과는 [ab] 일까 [ab성환] 일까.   결과는 [ab성환] 이다. 그렇다면 [ab]라는 결과를 얻고 싶다면 어떻게 해야 할까?
strncpy( name, "ab", 3 );  또는  strncpy( name, "ab", sizeof("ab"));  을 하면 된다.   즉 "ab"문자열 뒤에 있는 NULL 문자까지 같이 복사해 줘야 하는 것이다.
strcpy는 자동으로 마지막의 null 문자까지 복사해 주는 반면에 strncpy는 정확히 뒤에 지정한 길이만큼만 복사해 주기 때문이다.

보통의 경우 strncpy를 사용할 때 복사하는 길이를 target 변수의 사이즈대로 하게 된다. 하지만 target 변수의 길이가 작을 경우에는 반드시 마지막에 null 문자를 강제로 세트하는 로직이 필요한 것이다. 위의 매크로 예제 처럼 말이다.



반응형