gcc options: -Wformat
gcc options: -Wformat
Reqruies
- Compiler:
gcc 2.8이상- glibc:
2.2이상
printf나 scanf처럼 포맷 스트링(format string)을 사용하는 함수를 쓸 때, 인자의 타입을 잘못 전달하여 발생하는 오류를 자주 겪게 됩니다.이러한 실수를 컴파일 단계에서 미리 잡아낼 수 있도록 도와주는 핵심 옵션이 바로 -Wformat입니다.
Argument Type and Count Check
-Wformat 옵션이 실제 오류를 어떻게 감지하는지 간단한 예제로 살펴보겠습니다.format_warning.cc
Compile Outputbash
unsigned long 타입을 왜 %d로 출력하려 하는지 친절하게 경고를 띄워줍니다.인자의 타입뿐만 아니라, 포맷 스트링에서 요구하는 인자의 개수가 부족한 경우에도 아래와 같이 경고를 표시합니다.
format_warning2.cc
Compile Outputbash
GCC Documentation for -Wformat
-Wformat 옵션을 다음과 같이 설명하고 있습니다.gcc-7.5.0/Warning-OptionsDoc-Wformat -Wformat=n
Check calls to printf and scanf, etc.,
to make sure that the arguments supplied have types appropriate to the format string specified, and that the conversions specified in the format string make sense.
This includes standard functions, and others specified by format attributes (see Function Attributes),
in the printf, scanf, strftime and strfmon (an X/Open extension, not in the C standard) families (or other target-specific families).
Which functions are checked without format attributes having been specified depends on the standard version selected, and such checks of functions without the attribute specified are disabled by -ffreestanding or -fno-builtin.
The formats are checked against the format features supported by GNU libc version 2.2.
These include all ISO C90 and C99 features, as well as features from the Single Unix Specification and some BSD and GNU extensions.
Other library implementations may not support all these features; GCC does not support warning about features that go beyond a particular library's limitations.
However, if -Wpedantic is used with -Wformat, warnings are given about format features not in the selected standard version (but not for strfmon formats, since those are not in any version of the C standard).
Supported Functions in glibc
gcc 코드를 살펴보면 지원되는 함수 목록을 확인할 수 있습니다.
gcc/c-format.cc
printf, scanf, strftime 계열로 분류되는 것을 확인할 수 있습니다.va_arg() 등을 사용해 직접 정의한 함수를 -Wformat의 탐지 대상으로 추가하는 방법은 없을까요?사실__attribute__((format))을 소개하기 위해 그 기초가 되는-Wformat을 먼저 설명하고 있는 중입니다.
이를 간단히 gcc-7.5.0을 기준으로 살펴보겠습니다.
-Wformat-contains-nul
\0) 문자가 포함되어 무시되는 구간이 있는지 체크합니다.sample source code - format_contains_nul.cc
compile and check resultbash
-Wformat-extra-args
sample source code - format_extra_args.cc
compile and check resultbash
-Wformat-overflow
sprintf 등의 함수에서 버퍼 크기보다 더 큰 데이터가 기록되어 오버플로우가 발생할 가능성이 있는지 확인합니다.sample source code - format_overflow.cc
compile and check resultbash
sample source code - format_overflow.cc
compile and check resultbash
argv 값과 무관하게 포맷에 의해 이미 버퍼 오버플로우가 발생할 가능성이 있지만, 기본 -Wformat-overflow 옵션은 이를 감지하지 못합니다.compile with -Wformat-overflow=2bash
-Wformat-zero-length
sample source code - format_zero_length.cc
compile and check resultbash
하지만 다음과 같은 코드는 의외로 자주 발생합니다.
sometimes, these ridiculous codes appearc
-Wformat-nonliteral
sample source code - format_nonliteral.cc
compile and check resultbash
fmt를 const char로 명시하면 이 경고는 사라집니다.fmt)을 동적으로 변경해야 하는 코드를 작성해야 할 때도 있습니다.-Wformat-security
sample source code - format_security.cc
compile and check resultbash
security가 붙은 이유가 있습니다.%n 등으로 변경할 수 있고, 스택 오버플로우 등을 통해 인자를 조작하면 포맷 스트링 버그(Format String Bug) 등의 취약점 공격(Exploitation)이 가능한 코드가 되기 때문입니다.Format String Bug Exploitation 기법에 대해 별도의 포스트로 다뤄보겠습니다.-Wformat-signedness
signed인데 인자는 unsigned로 사용된 경우나 반대의 경우를 꼼꼼하게 잡아냅니다.sample source code - format_signedness.cc
compile and check resultbash
-Wformat-truncation
snprintf와 같이 길이를 지정하여 문자열을 다루는 함수에서, 데이터가 지정된 버퍼 크기에 맞춰 잘려나가는(truncation) 상황을 감지하고 경고합니다.sample source code - format_truncation.cc
compile and check resultbash