C 표준 라이브러리 함수를 위험하게 만드는 것은 무엇이며 대안은 무엇입니까?
CI를 배우는 동안 일부 기능 (예 :) gets()
은 안전하게 사용하기 어렵거나 불가능하기 때문에 절대 사용하지 말 것을 권장하는 리소스를 정기적으로 발견합니다 .
C 표준 라이브러리에 이러한 "절대 사용하지 않는"함수가 많이 포함되어있는 경우 해당 함수의 목록, 안전하지 않은 원인 및 대신 수행 할 작업을 알아야합니다.
지금까지 다음과 같은 기능을 배웠습니다.
- 메모리 덮어 쓰기를 방지 할 수 없습니다.
- 문자열을 null로 종료한다고 보장되지 않습니다.
- 통화 간 내부 상태 유지
일반적으로 사용하기에 안전하지 않은 것으로 간주됩니다. 이러한 동작을 나타내는 함수 목록이 있습니까? 안전하게 사용할 수없는 다른 유형의 기능이 있습니까?
예전에는 대부분의 문자열 함수에 경계 검사가 없었습니다. 물론 이전 함수를 삭제하거나 상한선을 포함하도록 서명을 수정하여 호환성을 깨뜨릴 수는 없습니다. 이제 거의 모든 기능에 대해 대체 "n"버전이 있습니다. 예를 들면 :
strcpy -> strncpy
strlen -> strnlen
strcmp -> strncmp
strcat -> strncat
strdup -> strndup
sprintf -> snprintf
wcscpy -> wcsncpy
wcslen -> wcsnlen
그리고 더.
안전하지 않은 함수를 사용하는 경우 gcc가 오류를보고하는 헤더 파일을 만드는 프로젝트 인 https://github.com/leafsr/gcc-poison 도 참조 하십시오 .
예, fgets(..., ..., STDIN)
는 gets()
크기 매개 변수를 사용하기 때문에에 대한 좋은 대안입니다 ( gets()
사실 C11에서는 C 표준에서 완전히 제거되었습니다). 참고 fgets()
정확히 드롭 인 교체하지 gets()
전자가 종료 포함하기 때문에, \n
전체 라인을 읽을 수의 버퍼 공간이 있다면 문자.
scanf()
입력이 예상 된 형식을 따르지 않으면 현명하게 복구 할 수 없기 때문입니다 (입력을 되 감고 다시 시도 할 수 없습니다). 형식이 잘못된 입력을 포기할 수 있다면 유용합니다. 여기서 A "더 나은"대안과 같은 입력 기능을 사용하는 것 fgets()
또는 fgetc()
입력 덩어리를 읽어 다음으로 스캔 sscanf()
또는 문자열과 같은 기능을 처리하여이를 분석 strchr()
하고 strtol()
. 의 "%s"
변환 지정자에 대한 특정 문제는 아래를 참조하십시오 scanf()
.
표준 C 함수는 아니지만 BSD 및 POSIX 함수 mktemp()
는 일반적으로 안전하게 사용할 수 없습니다. 파일의 존재 여부를 테스트 한 후 파일을 생성하는 사이에는 항상 TOCTTOU 경쟁 조건이 있기 때문입니다. mkstemp()
또는 tmpfile()
좋은 대체품입니다.
strncpy()
공간이 없으면 목적지를 null로 종료하지 않기 때문에 약간 까다로운 함수입니다. 일반적인 이름 임에도 불구하고이 함수는 일반 C 문자열과 다른 특정 스타일의 문자열을 만들기 위해 설계되었습니다. 문자열이 필드를 정확하게 채우는 경우 null 종결자가 필요하지 않은 알려진 고정 너비 필드에 저장된 문자열 (원래 UNIX 디렉터리) 이 스타일의 항목). 이러한 상황이 없다면이 기능을 피해야합니다.
atoi()
어떤 상황에서는 잘못된 선택이 될 수 있습니다. 변환하는 동안 오류가 발생했을 때를 알 수 없기 때문입니다 (예 : 숫자가의 범위를 초과 한 경우 int
). strtol()
이것이 당신에게 중요한 경우 사용하십시오 .
strcpy()
, strcat()
그리고 sprintf()
비슷한 문제에서로 고통을 gets()
- 그들은 당신이 대상 버퍼의 크기를 지정하는 것을 허용하지 않습니다. 적어도 이론적으로는 안전하게 사용하는 것이 여전히 가능합니다. 그러나 and 대신 사용하는 것이 훨씬 낫습니다 (를 사용할 수 있지만 위 참조). 반면에주의를 수행 하기위한이 , 대상 버퍼의 크기 에 대한 추가 할 최대 문자의 수이고 않는 널 종결을 포함하지. 관련 문자열 및 버퍼 크기를 이미 계산 한 경우 또 다른 대안은 또는 입니다.strncat()
snprintf()
strncpy()
n
snprintf()
n
strncat()
memmove()
memcpy()
같은 주제에서 scanf()
함수 계열을 사용하는 경우 일반을 사용하지 마십시오 . "%s"
예를 들어 대상의 크기를 지정하십시오 "%200s"
.
strtok()
호출 사이에 상태 정보를 저장하기 때문에 일반적으로 악한 것으로 간주됩니다. 다중 스레드 환경에서 그것을 실행하지 마십시오!
엄밀히 말하면 정말 위험한 기능이 하나 있습니다. 그것은 인 gets()
입력 프로그래머가 제어가 아니기 때문에. 여기에 언급 된 다른 모든 기능은 그 자체로 안전합니다. "좋음"과 "나쁨"은 방어 프로그래밍, 즉 전제 조건, 사후 조건 및 상용구 코드로 귀결됩니다.
의가 보자 strcpy()
, 예를 들면. 프로그래머가 함수 를 호출 하기 전에 충족해야하는 몇 가지 전제 조건이 있습니다. 두 문자열은 모두 0으로 끝나는 문자열에 대한 NULL이 아닌 유효한 포인터 여야하며 대상은 범위 내의 최종 문자열 길이로 충분한 공간을 제공해야합니다 size_t
. 또한 문자열이 겹칠 수 없습니다.
그것은 상당히 많은 전제 조건이며 strcpy()
. 프로그래머는 다음을 호출하기 전에 추가 상용구 코드를 사용하여 명시 적으로 테스트해야합니다 strcpy()
.
n = DST_BUFFER_SIZE;
if ((dst != NULL) && (src != NULL) && (strlen(dst)+strlen(src)+1 <= n))
{
strcpy(dst, src);
}
이미 겹치지 않고 0으로 끝나는 문자열을 조용히 가정합니다.
strncpy()
does include some of these checks, but it adds another postcondition the programmer must take care for after calling the function, because the result may not be zero-terminated.
strncpy(dst, src, n);
if (n > 0)
{
dst[n-1] = '\0';
}
Why are these functions considered "bad"? Because they would require additional boilerplate code for each call to really be on the safe side when the programmer assumes wrong about the validity, and programmers tend to forget this code.
Or even argue against it. Take the printf()
family. These functions return a status that indicate error and success. Who checks if the output to stdout or stderr succeeded? With the argument that you can't do anything at all when the standard channels are not working. Well, what about rescuing the user data and terminating the program with an error-indicating exit code? Instead of the possible alternative of crash and burn later with corrupted user data.
In a time- and money-limited environment it is always the question of how much safety nets you really want and what is the resulting worst case scenario? If it is a buffer overflow as in case of the str-functions, then it makes sense to forbid them and probably provide wrapper functions with the safety nets already within.
One final question about this: What makes you sure that your "good" alternatives are really good?
Any function that does not take a maximum length parameter and instead relies on an end-of- marker to be present (such as many 'string' handling functions).
Any method that maintains state between calls.
sprintf
is bad, does not check size, usesnprintf
gmtime
,localtime
--use gmtime_r
,localtime_r
To add something about strncpy most people here forgot to mention. strncpy can result in performance problems as it clears the buffer to the length given.
char buff[1000];
strncpy(buff, "1", sizeof buff);
will copy 1 char and overwrite 999 bytes with 0
Another reason why I prefer strlcpy (I know strlcpy is a BSDism but it is so easy to implement that there's no excuse to not use it).
View page 7 (PDF page 9) SAFECode Dev Practices
Edit: From the page -
strcpy family
strncpy family
strcat family
scanf family
sprintf family
gets family
strcpy
- again!
Most people agree that strcpy is dangerous, but strncpy is only rarely a useful replacement. It is usually important that you know when you've needed to truncate a string in any case, and for this reason you usually need to examine the length of the source string anwyay. If this is the case, usually memcpy is the better replacement as you know exactly how many characters you want copied.
e.g. truncation is error:
n = strlen( src );
if( n >= buflen )
return ERROR;
memcpy( dst, src, n + 1 );
truncation allowed, but number of characters must be returned so caller knows:
n = strlen( src );
if( n >= buflen )
n = buflen - 1;
memcpy( dst, src, n );
dst[n] = '\0';
return n;
'developer tip' 카테고리의 다른 글
"삭제 표시"항목은 언제 / 어떻게 최종적으로 제거됩니까? (0) | 2020.11.15 |
---|---|
Python : 주어진 사용자 이름 / 그룹 이름에 대한 uid / gid 찾기 (os.chown의 경우) (0) | 2020.11.15 |
모바일 용 메타 태그 – 사용해야합니까? (0) | 2020.11.14 |
data.table을 재구성하는 적절하고 빠른 방법 (0) | 2020.11.14 |
.java에서 JAR을 만드는 방법 (0) | 2020.11.14 |