momo zone

调核人的blog

gcc 4.5 以后strict-aliasing的问题

我之前总喜欢拿这个去面试其他人,结果后来重构os镜像后gcc升级到4.5发现原来该报 warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing],现在不报了。

看了一下gcc的log发现4.5中-Wstrict-aliasing分为几个级别,等级1检查的项目最多,-Wall 只是包含-Wstrict-aliasing=3。

`-Wstrict-aliasing=n'
     This option is only active when `-fstrict-aliasing' is active.  It
     warns about code that might break the strict aliasing rules that
     the compiler is using for optimization.  Higher levels correspond
     to higher accuracy (fewer false positives).  Higher levels also
     correspond to more effort, similar to the way -O works.
     `-Wstrict-aliasing' is equivalent to `-Wstrict-aliasing=n', with
     n=3.

     Level 1: Most aggressive, quick, least accurate.  Possibly useful
     when higher levels do not warn but -fstrict-aliasing still breaks
     the code, as it has very few false negatives.  However, it has
     many false positives.  Warns for all pointer conversions between
     possibly incompatible types, even if never dereferenced.  Runs in
     the front end only.

     Level 2: Aggressive, quick, not too precise.  May still have many
     false positives (not as many as level 1 though), and few false
     negatives (but possibly more than level 1).  Unlike level 1, it
     only warns when an address is taken.  Warns about incomplete
     types.  Runs in the front end only.

     Level 3 (default for `-Wstrict-aliasing'): Should have very few
     false positives and few false negatives.  Slightly slower than
     levels 1 or 2 when optimization is enabled.  Takes care of the
     common pun+dereference pattern in the front end:
     `*(int*)&some_float'.  If optimization is enabled, it also runs in
     the back end, where it deals with multiple statement cases using
     flow-sensitive points-to information.  Only warns when the
     converted pointer is dereferenced.  Does not warn about incomplete
     types.

再介绍一下C的aliasing概念:

aliasing指的是当有多个指针指向同一内存区域时,第二个及其后的指针都是第一个指针的aliasing。写C代码的人都知道这种情况是十分复杂的,容易引起内存重复释放,引用类型错误等等。所谓的strict-aliasing就是针对后者做的一项检查,即不同类型的指针不能指向同一个内存区域。举例:

int foo()
{
	long a = 4;
	int * p = (int *)&a;
	return *p+1;
}
gcc -Wstrict-aliasing=1 -Wall -O3 foo.c -o foo

编译器就会报错,说明违反strict-aliasing约定
如果不进行strict-aliasing检查,那么有可能会有个非常隐蔽的优化问题出现:

long _g;
int foo(int *b)
{
    _g = 1;
    *b = 3333333;
    return _g;
}

int main()
{
    printf("%d\n", foo((int *)(&_g)));
    return 0;
}

上面的代码用-O3编译结果是1,用-O0 编译是3333333。当然是后者正确,原因就是进行编译器优化的话,编译器认为foo函数中的b 指向的数据和_g没有关系,根据是b的指针类型和_g不同,所以优化编译时*b=3333333被认为为无效语句,结果也就是错的了。

Advertisements

4 responses to “gcc 4.5 以后strict-aliasing的问题

  1. xanpeng 2013年06月17日 @ 12:55 下午

    OpenSuse 11.4 64bit,gcc (4.5.1 20101208),`gcc -fno-strict-aliasing -O3 main.c -o main`编译最后一个例子,得到的结果是正确的3333333,不是文中说的1啊,如何解释?

    • lp007819 2013年06月17日 @ 1:46 下午

      -O3 默认开-fstrict-aliasing

      `-O2′
      Optimize even more. GCC performs nearly all supported
      optimizations that do not involve a space-speed tradeoff. As
      compared to `-O’, this option increases both compilation time and
      the performance of the generated code.

      `-O2′ turns on all optimization flags specified by `-O’. It also
      turns on the following optimization flags:
      -fthread-jumps
      -falign-functions -falign-jumps
      -falign-loops -falign-labels
      -fcaller-saves
      -fcrossjumping
      -fcse-follow-jumps -fcse-skip-blocks
      -fdelete-null-pointer-checks
      -fdevirtualize
      -fexpensive-optimizations
      -fgcse -fgcse-lm
      -finline-small-functions
      -findirect-inlining
      -fipa-sra
      -foptimize-sibling-calls
      -fpartial-inlining
      -fpeephole2
      -fregmove
      -freorder-blocks -freorder-functions
      -frerun-cse-after-loop
      -fsched-interblock -fsched-spec
      -fschedule-insns -fschedule-insns2
      -fstrict-aliasing -fstrict-overflow
      -ftree-switch-conversion -ftree-tail-merge
      -ftree-pre
      -ftree-vrp

      Please note the warning under `-fgcse’ about invoking `-O2′ on
      programs that use computed gotos.

      `-O3′
      Optimize yet more. `-O3′ turns on all optimizations specified by
      `-O2′ and also turns on the `-finline-functions’,
      `-funswitch-loops’, `-fpredictive-commoning’,
      `-fgcse-after-reload’, `-ftree-vectorize’ and `-fipa-cp-clone’
      options.

      你又用-fno-strict-aliasing关掉了优化,当然结果是正确的了

      • xanpeng 2013年06月17日 @ 2:41 下午

        也许我理解错误了,再叨扰一下。
        我只是觉得不管开关什么编译选项,这个程序如果输出1,都是让人吃惊的。

        我使用了这些编译选项,结果都是正确的333333,都是删掉./main后重编的:
        gcc -O3 main.c -o main
        gcc -Wall -O3 main.c -o main
        gcc -fstrict-aliasing -O3 main.c -o main
        gcc -Wstrict-aliasing=3 -Wall -O3 main.c -o main
        gcc -Wstrict-aliasing=2 -Wall -O3 main.c -o main
        gcc -Wstrict-aliasing=1 -Wall -O3 main.c -o main

      • lp007819 2013年06月20日 @ 12:45 上午

        不太清楚你的情况, 你确定是把代码copy过去的,一模一样?

        gcc不同的优化出现不同结果的确有此事,不仅仅是strict-aliasing

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: