5.1. C/C++ 에서의 위험

C 사용자는 경계 (bound) 를 검사하지 않는 위험한 함수가 경계가 절대로 초과되지 않을 것이다라는 보장을 하지 않는다면 이를 사용하는 것을 피해야 한다. 대부분의 경우에 있어 피해야 될 (또는 보호를 보장해야할) 함수는 strcpy(3), strcat(3), sprintf(3) (이와 유사한 vsprintf(3)) 과 gets(3) 인데 이들은 각각 strncpy(3), strncat(3), snprintf(3) 과 fgets(3) 으로 대체되어야한다. 밑부분의 논의를 보라. strlen(3) 함수도 있어야 될 종결 NIL 문자가 있을 것이다라고 보장하지 못한다면 피해야 한다. scanf(3), fscanf(3), sscant(3), vscanf(3), vsscanf(3) 과 vfscant(3) 과 같은 scanf() 계열도 사용하기에는 위험하다; 문자열의 최대 길이를 제어함이 없이 데이타를 문자열로 보내기 위해 이 함수들을 사용하지 마라 (%s 포맷이 특히 널리 알려진 문제이다). 어디에 사용하느냐에 따라 버퍼 오버런을 허용할 수 있는 다른 위험한 함수로는 realpath(3), getopt(3), getpass(3), streadd(3), strecpy(3) 과 strtrns(3) 들이 있다. getwd(3) 함수에 주의해야하는데 getwd(3) 함수에 보내지는 버퍼는 적어도 PATH_MAX 바이트 길이여야 한다.

불행히 snprintf() 변형들은 추가적인 문제를 갖고 있다. sprintf() 가 ISO 1990 (ANSI 1989) 표준내의 표준 C 함수이지만 공식적으로 snprintf() 는 표준 C 함수가 아니며 따라서 모든 시스템들이 snprintf() 를 포함하지 않는다. 더욱 안좋은 것은 어떤 시스템의 snprintf() 가 실제적으로 버퍼 오버플로우에 대한 보호를 제공하지 않는다는 것이다; 시스템들이 그저 sprintf 를 직접적으로 호출한다. 리눅스 libc4 의 예전 버전들은 이러한 끔직한 문제를 야기하는 "libbsd" 에 의존했으며 저자는 예전의 어떤 HP 시스템들도 동일한 문제가 있음을 들었다. snprintf 의 리눅스 현재 버전은 적절히 작동한다고 알려져 있다. 즉, 이는 실제적으로 요청된 경계를 침해하지 않는다. snprintf() 의 반환값도 마찬가지로 갖가지이다; Single Unix Specification (SUS) 버전 2 와 C99 표준은 snprintf() 가 반환하는 값에 차이가 있다. 마지막으로 적어도 snprintf 의 어떤 버전은 문자열이 NIL 로 끝날 것임을 보장하지 않는 것처럼 보인다; 문자열이 너무 길면 NIL 을 전혀 포함하지 않는다. GTK 의 기본으로 GNU C 라이브러리인 glibc 와는 다른 glib 라이브러리는 g_snprintf() 를 갖고 있음을 주목해라. 이는 일관성있는 반환 의미 체계를 갖으며 늘 NIL 로 끝나고 가장 중요한 것은 늘 버퍼 길이를 침범하지 않는다는 것이다.