海湾合作委员会,严格走样,和恐怖故事 [英] gcc, strict-aliasing, and horror stories

查看:172
本文介绍了海湾合作委员会,严格走样,和恐怖故事的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在<一个href=\"http://stackoverflow.com/questions/2906365/gcc-strict-aliasing-and-casting-through-a-union\">gcc-strict-aliasing-and-casting-through-a-union我问是否有人遇到与工会通过指针双关的问题。到目前为止,答案似乎是的没有

此问题是更广泛的:你有没有的任何的有关gcc和严格走样恐怖故事

背景:<一报价href=\"http://stackoverflow.com/questions/2771023/c99-strict-aliasing-rules-in-c-gcc/2771041#2771041\">AndreyT's回答C99-严格走样规则 - 在C-GCC :


  

严格走样规则植根于那名在C和C present ++自[标准化]次开始标准的组成部分。禁止通过另一种类型的左值访问一个类型的对象,该子句$在C89 / 90(6.3),以及在C ++ 98(3.10 / 15)。......这只是,并不是所有的编译器想要(或不敢)执行,或依赖于它。


好吧, GCC 现在敢于这样做,其 -fstrict走样开关。这已引起了一些问题。见,例如,优秀的文章 HTTP://davmac.word$p$pss.com/2009/10 / 有关Mysql的错误,并在<一的同样精彩讨论href=\"http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html\">http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html.

其他的一些相​​关的环节少:

如此重复,你有你自己的一个恐怖故事?问题的 -Wstrict走样表示当然会,是preferred。与其他C编译器也欢迎。

新增6月2日:在迈克尔·伯尔的答案,它所做的第一个链接 确实有资格作为一个恐怖故事,也许是一个位(2003年)日期。我做了一个快速测试,但问题显然已经消失。

来源:

 的#include&LT;&string.h中GT;
结构iw_event {/ *虚设! * /
    INT LEN;
};
字符* iwe_stream_add_event(
    字符*流/ *事件流* /
    字符*结束,/ * *流结束/
    结构iw_event * IWE,/ * *负载/
    INT event_len)/ *实时负载*的尺寸/
{
    / *检查,如果有可能* /
    如果((流+ event_len)LT;末端){
            iwe-&GT; LEN = event_len;
            的memcpy(流(字符*)IWE,event_len);
            流+ = event_len;
    }
    返回流;
}

具体的抱怨是:


  

有些用户抱怨称,当[上述] code时没有-fno严格走样编,写和memcpy的顺序被倒置(即一个假len为MEM-复制到流)。


编译code,使用 GCC 4.3.4在Cygwin王氏-O3(请纠正我,如果我错了 - 我的汇编器是一个有点生疏了!):

  _iwe_stream_add_event:
        pushl%EBP
        MOVL%ESP,EBP%
        pushl%EBX
        subl $ 20%ESP
        MOVL 8(EBP%),%EAX#流 - &GT; EAX%
        MOVL 20(%EBP),EDX%#event_len - &GT; %EDX
        莱亚尔(%EAX,EDX%),EBX%#总和 - &GT; EBX%
        CMPL 12(%EBP),EBX%比较#用之两端
        宰L2
        MOVL 16(%EBP),ECX%IWE# - &GT; %ECX
        MOVL%EDX,(ECX%)#event_len - &GT; iwe-&GT; LEN(!!)
        MOVL%EDX,8(%ESP)#event_len - &GT;堆
        MOVL%ECX,4(%ESP)#IWE - &GT;堆
        MOVL%EAX(%ESP)#流 - &GT;堆
        调用_memcpy
        MOVL%EBX,EAX%#总和 - &GT; RETVAL
L2:
        ADDL $ 20%ESP
        popl%EBX
        离开
        RET

和在迈克尔的回答第二个链接,

  *(无符号短*)及一= 4;

GCC 通常会(永远?)给予警告。但我的认为的一个有效的解决这个(对于 GCC )是使用:

 的#define CAST(类型,x)(((工会{typeof运算(x)的SRC,DST型;} *)及(X)) - &GT; DST)
// ...
CAST(无符号短,A)= 4;

我问过这样无论这是<一个确定href=\"http://stackoverflow.com/questions/2906365/gcc-strict-aliasing-and-casting-through-a-union\">gcc-strict-aliasing-and-casting-through-a-union,但至今没有人不同意。


解决方案

没有我自己的恐怖故事,但在这里是从Linus Torvalds公司一些报价(对不起,如果这些都已经在问题的链接引用之一):

http://lkml.org/lkml/2003/2/26/158


  

日期星期三,2003 9时22分15秒-0800 2月26日
  主题回复:不-fno严格走样编译无效
  距离Jean Tourrilhes&LT;>


  
  

在星期三,2003年2月26日在下午4点38分10秒+0100霍斯特·冯·品牌写道:


  
  

    

让Tourrilhes&LT;>说:


    
    

      

它看起来像一个编译器错误,我...
        有些用户抱怨说,当以下code是
      编译没有-fno严格走样,写的顺序和
      memcpy的反转(这意味着一个假len为MEM-复制到
      流)。
        code(从Linux /有/ NET / iw_handler.h):

 静态内嵌的char *
iwe_stream_add_event(字符*流/ *事件流* /
                     字符*结束,/ * *流结束/
                    结构iw_event * IWE,/ * *负载/
                     INT event_len)/ *实时负载*的尺寸/
{
  / *检查,如果有可能* /
  如果((流+ event_len)LT;末端){
      iwe-&GT; LEN = event_len;
      的memcpy(流(字符*)IWE,event_len);
      流+ = event_len;
  }
  返回流;
}


      
      

恕我直言,编译器应该有足够的上下文来知道
      重新排序是很危险的。任何建议,使这个简单的code以上
      防弹受到欢迎。


    
    
    

编译器是免费的假设的char *流和结构iw_event * IWE点
    分离的存储区域,由于严格的锯齿。


  
  
  

这是真实的,这不是我抱怨的问题。


  
  

和林纳斯·托瓦兹的上述评论:


  
  

让Tourrilhes写道:
  >


  
  

    

它看起来像一个编译器错误,我...


  
  
  

为什么你觉得内核使用-fno严格走样?


  
  

gcc的人们更感兴趣的是试图找出什么都可以
  由C99规格得到比约让事情实际上工作的。该
  特别是走样code是不值得实现,它只是不
  可能三立告诉GCC的时候有些东西别名。


  
  

    

有些用户抱怨称,当以下code是
    编译没有-fno严格走样,写的顺序和
    memcpy的反转(这意味着一个假len为MEM-复制到
    流)。


  
  
  

问题是我们内联的memcpy(),在这一点GCC将不
  关心一个事实,即它可以别名,所以他们就会重新排序
  一切并声称这是出自己的过错。即使是没有理智
  这是对我们甚至告诉GCC这件事。


  
  

我试图让几年前一个健全的方式,与海合会开发商真的
  不关心这方面的真实世界。我会,如果感到惊讶
  就变了,由我已经看到的答复来看。


  
  

我不会刻意去争取它。


  
  

莱纳斯


HTTP://www.mail-archive。 com/linux-btrfs@vger.kernel.org/msg01647.html


  

键入基于走样是的的。它是如此令人难以置信的愚蠢,它甚至不是滑稽。这是坏了。和gcc拿着破的概念,并使其成为由这封信的最法的东西没有任何意义变得更加如此。


  
  

...


  
  

我知道一个的实际上的是海湾合作委员会将重新排序写访问的人清楚地(静态)相同的地址。 GCC会突然觉得

 无符号长;1 = 5;
*(无符号短*)及一= 4;


  
  

可以重新排序,以将其设置为4第一(因为显然他们没有别名 - 通过阅读标准),然后因为现在的分配'1 = 5'后来,4分配可能是完全省略!如果有人抱怨说,编译器是疯了,编译器的人会说:nyaah,nyaah的标准的人说,我们能做到这一点,绝对没有自省询问是否作出任何意义。


In gcc-strict-aliasing-and-casting-through-a-union I asked whether anyone had encountered problems with union punning through pointers. So far, the answer seems to be No.

This question is broader: Do you have any horror stories about gcc and strict-aliasing?

Background: Quoting from AndreyT's answer in c99-strict-aliasing-rules-in-c-gcc:

"Strict aliasing rules are rooted in parts of the standard that were present in C and C++ since the beginning of [standardized] times. The clause that prohibits accessing object of one type through a lvalue of another type is present in C89/90 (6.3) as well as in C++98 (3.10/15). ... It is just that not all compilers wanted (or dared) to enforce it or rely on it."

Well, gcc is now daring to do so, with its -fstrict-aliasing switch. And this has caused some problems. See, for example, the excellent article http://davmac.wordpress.com/2009/10/ about a Mysql bug, and the equally excellent discussion in http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html.

Some other less-relevant links:

So to repeat, do you have a horror story of your own? Problems not indicated by -Wstrict-aliasing would, of course, be preferred. And other C compilers are also welcome.

Added June 2nd: The first link in Michael Burr's answer, which does indeed qualify as a horror story, is perhaps a bit dated (from 2003). I did a quick test, but the problem has apparently gone away.

Source:

#include <string.h>
struct iw_event {               /* dummy! */
    int len;
};
char *iwe_stream_add_event(
    char *stream,               /* Stream of events */
    char *ends,                 /* End of stream */
    struct iw_event *iwe,       /* Payload */
    int event_len)              /* Real size of payload */
{
    /* Check if it's possible */
    if ((stream + event_len) < ends) {
            iwe->len = event_len;
            memcpy(stream, (char *) iwe, event_len);
            stream += event_len;
    }
    return stream;
}

The specific complaint is:

Some users have complained that when the [above] code is compiled without the -fno-strict-aliasing, the order of the write and memcpy is inverted (which means a bogus len is mem-copied into the stream).

Compiled code, using gcc 4.3.4 on CYGWIN wih -O3 (please correct me if I am wrong--my assembler is a bit rusty!):

_iwe_stream_add_event:
        pushl       %ebp
        movl        %esp, %ebp
        pushl       %ebx
        subl        $20, %esp
        movl        8(%ebp), %eax       # stream    --> %eax
        movl        20(%ebp), %edx      # event_len --> %edx
        leal        (%eax,%edx), %ebx   # sum       --> %ebx
        cmpl        12(%ebp), %ebx      # compare sum with ends
        jae L2
        movl        16(%ebp), %ecx      # iwe       --> %ecx
        movl        %edx, (%ecx)        # event_len --> iwe->len (!!)
        movl        %edx, 8(%esp)       # event_len --> stack
        movl        %ecx, 4(%esp)       # iwe       --> stack
        movl        %eax, (%esp)        # stream    --> stack
        call        _memcpy
        movl        %ebx, %eax          # sum       --> retval
L2:
        addl        $20, %esp
        popl        %ebx
        leave
        ret

And for the second link in Michael's answer,

*(unsigned short *)&a = 4;

gcc will usually (always?) give a warning. But I believe a valid solution to this (for gcc) is to use:

#define CAST(type, x) (((union {typeof(x) src; type dst;}*)&(x))->dst)
// ...
CAST(unsigned short, a) = 4;

I've asked SO whether this is OK in gcc-strict-aliasing-and-casting-through-a-union, but so far nobody disagrees.

解决方案

No horror story of my own, but here are some quotes from Linus Torvalds (sorry if these are already in one of the linked references in the question):

http://lkml.org/lkml/2003/2/26/158:

Date Wed, 26 Feb 2003 09:22:15 -0800 Subject Re: Invalid compilation without -fno-strict-aliasing From Jean Tourrilhes <>

On Wed, Feb 26, 2003 at 04:38:10PM +0100, Horst von Brand wrote:

Jean Tourrilhes <> said:

It looks like a compiler bug to me... Some users have complained that when the following code is compiled without the -fno-strict-aliasing, the order of the write and memcpy is inverted (which mean a bogus len is mem-copied into the stream). Code (from linux/include/net/iw_handler.h) :

static inline char *
iwe_stream_add_event(char *   stream,     /* Stream of events */
                     char *   ends,       /* End of stream */
                    struct iw_event *iwe, /* Payload */
                     int      event_len)  /* Real size of payload */
{
  /* Check if it's possible */
  if((stream + event_len) < ends) {
      iwe->len = event_len;
      memcpy(stream, (char *) iwe, event_len);
      stream += event_len;
  }
  return stream;
}

IMHO, the compiler should have enough context to know that the reordering is dangerous. Any suggestion to make this simple code more bullet proof is welcomed.

The compiler is free to assume char *stream and struct iw_event *iwe point to separate areas of memory, due to strict aliasing.

Which is true and which is not the problem I'm complaining about.

And Linus Torvald's comment on the above:

Jean Tourrilhes wrote: >

It looks like a compiler bug to me...

Why do you think the kernel uses "-fno-strict-aliasing"?

The gcc people are more interested in trying to find out what can be allowed by the c99 specs than about making things actually work. The aliasing code in particular is not even worth enabling, it's just not possible to sanely tell gcc when some things can alias.

Some users have complained that when the following code is compiled without the -fno-strict-aliasing, the order of the write and memcpy is inverted (which mean a bogus len is mem-copied into the stream).

The "problem" is that we inline the memcpy(), at which point gcc won't care about the fact that it can alias, so they'll just re-order everything and claim it's out own fault. Even though there is no sane way for us to even tell gcc about it.

I tried to get a sane way a few years ago, and the gcc developers really didn't care about the real world in this area. I'd be surprised if that had changed, judging by the replies I have already seen.

I'm not going to bother to fight it.

Linus

http://www.mail-archive.com/linux-btrfs@vger.kernel.org/msg01647.html:

Type-based aliasing is stupid. It's so incredibly stupid that it's not even funny. It's broken. And gcc took the broken notion, and made it more so by making it a "by-the-letter-of-the-law" thing that makes no sense.

...

I know for a fact that gcc would re-order write accesses that were clearly to (statically) the same address. Gcc would suddenly think that

unsigned long a;

a = 5;
*(unsigned short *)&a = 4;

could be re-ordered to set it to 4 first (because clearly they don't alias - by reading the standard), and then because now the assignment of 'a=5' was later, the assignment of 4 could be elided entirely! And if somebody complains that the compiler is insane, the compiler people would say "nyaah, nyaah, the standards people said we can do this", with absolutely no introspection to ask whether it made any SENSE.

这篇关于海湾合作委员会,严格走样,和恐怖故事的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆