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 | 트랙백 | 덧글(0)
트랙백 주소 : http://studyfoss.egloos.com/tb/5377719
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]

:         :

:

비공개 덧글

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

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

최근 등록된 덧글
informsi yang bagus dan be..
by pordanaia at 08/05
Informsi yang bagus dan b..
by jamalsu at 08/01
as inforasi yang menarik http..
by jamalsu at 07/22
최근 등록된 트랙백
Tod's Ferrari Homme
by Tods Pas Cher,Kodak did ..
Mocassin Femme
by Mocassins Homme, I got so..
natural garcinia cambogia
by
rss

skin by jiinny


X