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