gcc options: -Wformat

Explore the -Wformat option in GCC to detect format string errors and security vulnerabilities at compile time.
March 25, 2026

gcc options: -Wformat

Reqruies
  • Compiler: gcc 2.8 이상
  • glibc: 2.2 이상
C 언어 개발 시 printfscanf처럼 포맷 스트링(format string)을 사용하는 함수를 쓸 때, 인자의 타입을 잘못 전달하여 발생하는 오류를 자주 겪게 됩니다.
이러한 실수를 컴파일 단계에서 미리 잡아낼 수 있도록 도와주는 핵심 옵션이 바로 -Wformat입니다.

Argument Type and Count Check

먼저 -Wformat 옵션이 실제 오류를 어떻게 감지하는지 간단한 예제로 살펴보겠습니다.
format_warning.c
c
Compile Output
bash
컴파일러는 unsigned long 타입을 왜 %d로 출력하려 하는지 친절하게 경고를 띄워줍니다.
인자의 타입뿐만 아니라, 포맷 스트링에서 요구하는 인자의 개수가 부족한 경우에도 아래와 같이 경고를 표시합니다.
format_warning2.c
c
Compile Output
bash

GCC Documentation for -Wformat

GCC 공식 문서에서는 -Wformat 옵션을 다음과 같이 설명하고 있습니다.
gcc-7.5.0/Warning-Options
Doc

-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

glibc 2.2 이후의 일부 표준 함수들이 지원된다고 명시되어 있습니다.
그렇다면 glibc의 어떤 함수들이 -Wformat을 지원할까요?
gcc 코드를 살펴보면 지원되는 함수 목록을 확인할 수 있습니다.
gcc/c-format.c
c
gcc 코드를 상세히 이해하기는 복잡하지만, 크게 printf, scanf, strftime 계열로 분류되는 것을 확인할 수 있습니다.
그렇다면 glibc 표준 함수 대신, 사용자가 va_arg() 등을 사용해 직접 정의한 함수를 -Wformat의 탐지 대상으로 추가하는 방법은 없을까요?
앞서 살펴본 문서에 언급된 것처럼 attribute((format))을 사용하면 됩니다.
사실 __attribute__((format))을 소개하기 위해 그 기초가 되는 -Wformat을 먼저 설명하고 있는 중입니다.
-Wformat 계열의 옵션들에는 여러 종류가 있습니다.
이를 간단히 gcc-7.5.0을 기준으로 살펴보겠습니다.

-Wformat-contains-nul

포맷 스트링 내부에 널(NUL, \0) 문자가 포함되어 무시되는 구간이 있는지 체크합니다.
sample source code - format_contains_nul.c
c
compile and check result
bash

-Wformat-extra-args

포맷 지정자보다 더 많은 수의 인자가 전달된 경우를 감지합니다.
sample source code - format_extra_args.c
c
compile and check result
bash

-Wformat-overflow

sprintf 등의 함수에서 버퍼 크기보다 더 큰 데이터가 기록되어 오버플로우가 발생할 가능성이 있는지 확인합니다.
sample source code - format_overflow.c
c
compile and check result
bash
그렇다면 컴파일 타임에 크기를 예측하기 어려운 경우는 어떨까요?
sample source code - format_overflow.c
c
compile and check result
bash
사실 argv 값과 무관하게 포맷에 의해 이미 버퍼 오버플로우가 발생할 가능성이 있지만, 기본 -Wformat-overflow 옵션은 이를 감지하지 못합니다.
이러한 경우에는 -Wformat-overflow의 검사 레벨을 2로 높여 지정할 수 있습니다.
compile with -Wformat-overflow=2
bash

-Wformat-zero-length

포맷 스트링의 길이가 0인 경우를 경고합니다.
sample source code - format_zero_length.c
c
compile and check result
bash
사실 위와 같이 직접적으로 코드를 작성할 일은 드뭅니다.
하지만 다음과 같은 코드는 의외로 자주 발생합니다.
sometimes, these ridiculous codes appear
c

-Wformat-nonliteral

포맷 스트링이 문자열 리터럴이 아닌 경우를 경고합니다.
sample source code - format_nonliteral.c
c
compile and check result
bash
fmtconst char로 명시하면 이 경고는 사라집니다.
하지만 포맷 스트링(fmt)을 동적으로 변경해야 하는 코드를 작성해야 할 때도 있습니다.
이런 경우에는 종종 무시 코드를 추가하여 해당 옵션의 경고를 회피하기도 합니다.

-Wformat-security

포맷이 내부 문자열(internal string) 상수(literal)가 아니면서, 인자가 없는 경우를 감지합니다.
sample source code - format_security.c
c
compile and check result
bash
이 경우가 왜 감지되는 것일까요? 옵션 이름에 security가 붙은 이유가 있습니다.
만약 내부 관리용 문자열(internal string)이 아니라 외부의 입력 등에 의해 결정되는 경우, 포맷 스트링을 %n 등으로 변경할 수 있고, 스택 오버플로우 등을 통해 인자를 조작하면 포맷 스트링 버그(Format String Bug) 등의 취약점 공격(Exploitation)이 가능한 코드가 되기 때문입니다.
즉, 보안 상 심각한 구멍이 있는 코드라는 뜻입니다.
기회가 된다면 Format String Bug Exploitation 기법에 대해 별도의 포스트로 다뤄보겠습니다.

-Wformat-signedness

이름에서 알 수 있듯이, 포맷 지정자가 signed인데 인자는 unsigned로 사용된 경우나 반대의 경우를 꼼꼼하게 잡아냅니다.
sample source code - format_signedness.c
c
compile and check result
bash

-Wformat-truncation

snprintf와 같이 길이를 지정하여 문자열을 다루는 함수에서, 데이터가 지정된 버퍼 크기에 맞춰 잘려나가는(truncation) 상황을 감지하고 경고합니다.
sample source code - format_truncation.c
c
compile and check result
bash

Conclusion

위에서 살펴본 문제들은 얼핏 단순한 경고처럼 보일 수 있지만, 상황에 따라 런타임에 스택 오버플로우가 발생하거나 애플리케이션의 보안 취약점(Security hole)으로 이어질 수 있습니다.
따라서 프로젝트가 일정 규모 이상으로 성장할 때, 이러한 위험 요소들을 컴파일 단계에서 미리 인지하고 수정할 수 있다면 프로젝트 완성도에 큰 이점이 됩니다.
그러므로 가급적이면 컴파일 옵션에 -Wformat 또는 -Werror=format을 활성화하여 사소한 실수를 방지하는 것을 권장합니다.
Jooojub
System S/W engineer
Explore Tags
Series
    Recent Post
    © 2026. jooojub. All right reserved.