9.1. C/C++

C 및 C++ 프로그램과 관련된 가장 커다란 보안 문제중의 하나는 버퍼 오버플로우로 더욱 자세한 정보는 5장 을 보라. C 는 예외 처리를 지원하지 않는다는 추가적인 약점을 갖고 있는데 이는 중대한 에러 상황을 무시하는 프로그램 작성을 용이하게 한다.

C 와 C++ 에서 문자 타입 ``char" 은 컴파일러와 머신에 따라 signed 또는 unsigned 될 수 있다 는것은 한가지 혼란스런 문제이다. 상위 비트가 설정되어 있는 signed char 이 정수로 저장될 때 결과는 음수일 것인데 어떤 경우 이는 악용될 수 있다. 일반적으로 127 (0x71) 보다 큰 값을 가질 수도 있는 문자 데이타를 다룰때 버퍼, 포인터와 캐스트에 대해서는 char 또는 signed char 대신 ``unsigned char" 를 사용해라.

C 와 C++ 은 타입 검사 지원에 있어 정의상 상당히 모호하지만 코드에서 모호할 필요는 없다. 가능한 한 많은 컴파일러 경고를 켜고 코드를 변경해서 이와함께 새롭게 컴파일하며 모든 함수 호출이 정확한 타입을 사용하는 지를 보장하기 위해 별도의 헤더 (.h) 파일에 ANSI 원형을 엄격히 사용해라. gcc 를 사용한 C 또는 C++ 컴파일의 경우 적어도 많은 경고 메시지를 켜는 다음을 컴파일 플래그로 사용해 모든 경고를 제거하려고 해라 (어떤 경고는 더욱 높은 최적화 수준에서 수행되는 데이타 플로우 분석에 의해서만 탐지될 수 있기 때문에 -O2 가 사용됨을 주목해라):
gcc -Wall -Wpointer-arith -Wstrict-prototypes -O2
또한 "-W -pedantic" 을 사용할 수도 있다.

많은 C/C++ 컴파일러는 부정확한 포맷 문자열들을 탐지할 수 있다. 예를 들어 gcc 는 함수를 표시하기 위해 __attribute__() 기능 (C 확장) 을 사용한다면 이 함수에 대한 부정확한 포맷 문자열에 대해 경고를 할 수 있으며 코드를 이식불가능하게 만들지 않고서도 이 기능을 사용할 수 있다. 다음은 헤더 (.h) 파일에 있는 예이다:
 /* in header.h */
 #ifndef __GNUC__
 #  define __attribute__(x) /*nothing*/
 #endif

 extern void logprintf(const char *format, ...)
    __attribute__((format(printf,1,2)));
 extern void logprintva(const char *format, va_list args)
    __attribute__((format(printf,1,0)));
"format" 속성은 "printf" 또는 "scanf" 를 취하며 숫자들은 각각 포맷 문자열의 매개변수와 첫번째 variadic 매개변수의 수이다. GNU docs 에 이들에 대해 잘 설명되어 있다. "noreturn" 와 "const" 와 같은 다른 __attribute__ 기능들도 있음을 주목해라.

가능한 열거되는 값들을 정의하기 위해 특별한 값을 갖는 ``char" 또는 ``int" 가 아닌 ``enum" 을 사용해라. 이는 컴파일러가 모든 합법적인 값들이 다루어졌는지 결정하기 위해 사용될 수 있는 switch 문의 값들에 대해 특히 유용하다.