【问题标题】:Is there any way to get a warning in eg. GCC or Clang about this strict aliasing violation?有没有办法在例如得到警告。 GCC 或 Clang 关于这种严格的别名违规?
【发布时间】:2021-08-06 22:09:31
【问题描述】:

这是一个严格的别名违规的基本原理是 缓冲区已声明类型 char 数组并被 指向结构的指针

#include<string.h>
#include<stdalign.h>
#include<stdio.h>

struct thing {
  int a;
  char x;
};

int main() {
  char alignas(struct thing) buffer[128];
  
  struct thing s = {10,'a'};

  struct thing *ptr = memcpy(buffer,&s,sizeof(struct thing));
  
  // violation at ptr->a
  printf("%d\n",ptr->a);

  return 0;
}

【问题讨论】:

  • 严格的别名违规一般不能静态检测。
  • @Barmar 这里可以推导出ptr是通过memcpy来自&amp;s,所以指向s。此外,ptr-&gt;a 在分配了s.a 的同一基本块中被访问;数据流分析很容易表明最后存储到ptr-&gt;a 实际上是到s.a。也许 GCC 根本不会通过memcpy 跟踪指针出处。使用memcpy 返回值的代码非常少见。
  • 如果不使用memcpy 的返回值,而是忽略memcpy 的返回值,然后直接从&amp;s 初始化ptr,是否有区别?这个问题的目的是确定是否是这个问题:没有通过memcpy函数跟踪指针数据流。
  • @kaz 作为记录,我在这样做时找不到任何警告的方法struct thing *ptr = (struct thing*) &amp;buffer[0]; ptr-&gt;a = 10; ptr-&gt;x = 'a';
  • @anonymouscoward,当buffer不是数组时会产生警告,有意思...

标签: c strict-aliasing


【解决方案1】:

警告所有违反 N1570 6.5p7 中所写约束的构造的编译器会生成大量关于所有质量实现都将毫无困难地支持的构造的警告。标准的这些部分有意义的唯一方法是,如果作者期望质量实现能够扩展语言的语义以支持用例,即使标准没有强制要求,他们也没有理由不这样做支持。呈现的代码中说明的用例就是一个例子。

尽管标准不会禁止实现使用 N1570 6.5p7 作为无意义行为的借口,即使在对象仅用作单一类型的存储的情况下,规则的明确目的是描述实现的情况是否需要考虑指针别名的可能性。禁止有争议的特定构造即使在存储仅用作单一类型的情况下也无助于实现这一目标。如果代码要在buffer 上使用下标运算符,除了通过struct thing* 访问存储之外,编译器可能会合理地无法识别使用后一个左值的访问可能与使用前一个左值的访问进行交互的可能性。然而,在呈现的代码中,存储仅用作类型struct thing 或通过memcpy,没有理由禁止的用例。以仅禁止使用char[] 来保存某些其他类型的数据的方式编写规则,在它也被下标的情况下肯定会增加复杂性,但不会期望编译器支持他们会支持的任何结构'反正不支持。

如果该标准旨在将程序描述为正确或不正确的程序,那么编写更详细的规则是值得的。但是,由于它没有尝试区分错误的构造和正确但“不可移植”的构造(从某种意义上说,可能存在一些没有有意义地处理它们的实现),因此没有必要尝试明确识别并提供编译器没有理由不进行有意义处理的所有构造。

【讨论】:

    猜你喜欢
    • 2021-08-08
    • 1970-01-01
    • 2017-02-25
    • 2019-06-11
    • 2012-05-06
    • 1970-01-01
    • 2020-04-11
    相关资源
    最近更新 更多