Egloos | Log-in
F/OSS study
F/OSS study
[gcc] signed overflow
gcc: 4.5.0


C 언어에서는 signed integer 타입에 대한 overflow 시의 행동을 정의하지 않고 있다.
(반면에 unsigned integer 타입에 대해서는 (wrap 되도록) 잘 정의되어 있다.)
따라서 이러한 행동을 일으킬 수 있는 코드를 작성해서는 안되는 것이 맞지만
현실에서는 종종 이러한 동작에 (의도적이든 아니든 간에) 의존하고 있는 코드를 볼 수 있을 것이다.

아주 극단적이긴 하지만 흥미로운(?) 예제를 하나 살펴보기로 하자.

/* overflow.c */

#include <limits.h>
#include <stdio.h>

int foo(int x)
{
  return (INT_MAX - 16 < x) && (x + 32 < INT_MAX);
}

int main(void)
{
#define test(exp)  printf(#exp " = %d\n", exp)
  test(foo(INT_MAX-8));
#undef test

  return 0;
}

foo() 함수는 x의 범위를 검사하는 일을 한다.
foo()가 1을 반환하려면 먼저 x가 INT_MAX - 16보다 큰 수여야 한다.
또한 x + 32는 INT_MAX보다 작아야 하는데 이런 일이 가능할까?

만약 음수 표현으로 2의 보수 형식을 취하는 환경의 경우 signed integer의 overflow를
그냥 일반 unsigend integer의 덧셈처럼 수행한 후 음수 형식으로 처리한다고 하면 가능하다.
즉, x86/Linux/gcc에서는 x에 INT_MAX - 8이 사용되었을 때 가능하다.

위의 프로그램을 컴파일하여 실행해보면 다음과 같은 결과가 출력될 것이다.

$ gcc overflow.c
$ a.out
foo(INT_MAX-8) = 1

즉 INT_MAX + 16이 음수가 되었기 때문에 이러한 결과가 나온 것이다.
하지만 이 코드를 최적화 옵션 -O2를 주어 컴파일 하면 다음과 같은 결과를 볼 수 있다.

$ gcc -O2 overflow.c
$ a.out
foo(INT_MAX-8) = 0

동일한 코드가 다른 결과를 출력하였다!!
이는 -O2 최적화 옵션으로 인해 -fstrict-overflow 옵션이 활성화되었기 때문이다.
-fstrict-overflow 옵션은 overflow에 대한 행동을 해당 언어의 표준에 따라 엄격하게 해석하도록 하여
gcc가 최적화를 수행할 때 더 효율적인 코드를 생성할 수 있도록 하기 위한 것이다.

즉, 프로그래머가 overflow가 발생하지 않도록 코드를 잘 작성했다고 믿고
컴파일 시에 overflow에 대한 고려를 전혀 하지 않고서 최적화를 수행한다.
보다 구체적으로 말하면 어떤 정수값에 양수를 더하면 그 결과는 항상 처음의 정수값보다 크다고 생각한다.

위의 경우 C 언어에서 overflow가 정의되지 않았으므로 해당 코드에서 overflow가 발생하지 않을 것이라고 가정하여
(x + 32 < INT_MAX) 부분을 항상 false가 되도록 만들기 때문에 항상 0을 리턴한다.
(overflow가 없다면 INT_MAX-16 보다 큰 수가 32를 더해서 INT_MAX보다 작아질 수가 없다)

따라서 이러한 코드에 의존하고 있다면 컴파일 시 명시적으로 -f[no-]strict-overflow 옵션을 이용해야 한다.
위의 예제에서도 컴파일 시에 이 옵션을 적용해 보면 결과가 달라지는 것을 볼 수 있다.

또 다른 예제를 하나 보자.
이 예제는 -fstrict-overflow와 최적화 옵션이 함께 적용될 때만 결과가 달라지는데
특히나 loop에서 signed integer 타입의 인덱스 변수를 사용하는 경우가 상당히 빈번하므로
주의깊게 살펴볼 필요가 있을 것이다.

/* overflow-loop.c */

int bar(void)
{
  int i, j = 0;
  for (i = 1; i > 0; i += i)
    j++;

  return j;
}

int main(void)
{
  return bar();
}

위의 예제는 -O2 옵션이 주어진 경우에만 (따라서 -fstrict-overflow 옵션도 적용된 경우)
무한 루프에 빠지게 된다. (궁금하다면 직접 한 번 실행보길 바란다.. ^^)

비슷한 옵션으로 -fwrapv가 있다.
이는 signed integer의 overflow가 항상 wrapping되도록 명시적으로 알려주는 역할을 한다.
따라서 -fno-strict-overflow와 비슷한 결과를 얻을 수 있지만
코드의 최적화에 영향을 많이 끼치므로 원래와는 많은 차이가 있는 코드가 생성된다고 한다.


=== 참고 문헌 ===


by namhyung | 2010/08/13 02:39 | System | 트랙백 | 덧글(1)
트랙백 주소 : http://studyfoss.egloos.com/tb/5377719
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by 로양이 at 2019/10/17 12:07
오우정보감사요 헤매고 있는뎁 완죤 많은 도움이 되었어용

:         :

:

비공개 덧글

◀ 이전 페이지 다음 페이지 ▶

카테고리
General
Application
System
Kernel
Book
Tips
태그
git glibc elf vcs blktrace algorithm memory CARM block-layer gcc C emacs scm linux computer-architecture bash x86 patch build binutils script sed synchronization SMP awk CAaQA3 compiler documentation kernel perf
전체보기
이글루 파인더

최근 등록된 덧글
많이 배우고 갑니다. 방장 만세.
by 머떨이 at 12/04
오우정보감사요 헤매고 있는뎁 완..
by 로양이 at 10/17
상세하고 깔끔한 설명 정말 감사..
by 일로 at 09/24
최근 등록된 트랙백
[linux] signal handler 를 좀..
by 비더탑
Tod's Ferrari Homme
by Tods Pas Cher,Kodak did ..
Mocassin Femme
by Mocassins Homme, I got so..
rss

skin by jiinny


X