【问题标题】:Violating strict aliasing does not always produce a compiler warning违反严格别名并不总是产生编译器警告
【发布时间】:2018-04-19 10:32:34
【问题描述】:

严格混叠让我陷入了一个循环。这是代码。

我有课

#include <arpa/inet.h>
#include <net/route.h>

class Alias
{
public:
   struct rtentry rt;
   struct sockaddr_in *address;  

   void try_aliasing()
   {
       address = (struct sockaddr_in *)&rt.rt_dst;
       address->sin_family = AF_INET;
   }
};


如果我像这样使用它:

int main()
{
   Alias a ;
   a.try_aliasing();
   return 0;
}


它显示:

warning:dereferencing pointer '<anonymous>' does break strict-aliasing rules


但是,如果我将类用作:

int main()
{
   Alias *a = new Alias();
   a->try_aliasing();
   return 0;
}


它编译得很好。
两次编译均使用:

g++ a.cpp -Wall -O2


查看了一些关于严格别名的线程,但他们未能为我清除这种行为的原因。

【问题讨论】:

标签: c++ undefined-behavior strict-aliasing


【解决方案1】:

在编译器能够生成“严格别名”警告的大多数情况下,他们可以很容易地识别使用不同左值的存储操作之间的关系。标准不要求编译器使用不同类型的左值识别对存储的访问的原因是避免要求他们悲观地假设别名在他们没有理由期望它的情况下 [和因此没有理由对此发出任何警告]。

正如所写,标准不承认 任何 非字符类型的左值可以从另一个左值派生并用于访问存储作为其自己的类型的情况。甚至是这样的:

struct foo {int x;} s = {0};
s.x = 1;

调用UB,因为它使用int 类型的左值来访问struct foo 类型的对象的存储。标准的作者依靠编译器作者来识别常识意味着他们应该以可预测的方式行事而不考虑标准是否实际需要它的情况。我认为任何编译器都不会愚蠢到无法识别s.x 上的操作实际上是s 上的操作,并且还有许多其他情况,标准的作者认为编译器有意识识别这样的事情没有被命令这样做。

不幸的是,一些编译器编写者已经开始将这些规则视为假设代码看起来会使用另一种类型的左值访问一种类型的存储的理由,而不是仅仅对代码做出这样的假设看起来确实如此。给定类似的东西:

void doSomehing(structs s2 *p);

void test(struct s1 *p)
{
  doSomething((struct s2*)p};
}

有几种方法可以调用 test 之类的东西:

1. It might receive a pointer to a `struct s1`, which `doSomething` will need to operate upon [perhaps using the Common Initial Sequence guarantee] as though it is a `struct s2`.  Further, either:

1a. During the execution of `doSomething` storage accessed exclusively via pointers derived from a struct s2 like the one that was passed in will be accessed exclusively via such means, or...

1b. During the execution of `doSomething` storage accessed via things of that type will also be accessed via other unrelated means.

2. It might receive a pointer to a `struct s2`, which has been cast to a `struct s1*` for some reason in the calling code.

3. It might receive a pointer to a `struct s1`, which `doSomething` will process as though it's a `struct s1`, despite the fact that it accepts a parameter of type `struct s2`.

编译器可能会观察到其行为由标准定义的情况都不太可能,因此决定在此基础上发出警告。另一方面,到目前为止,最常见的情况是#1a,编译器确实应该能够以可预测的方式毫无困难地处理,无论标准是否要求,通过确保对 @ 类型的事物的任何操作在函数内执行的 987654329@ 在调用之前的 struct s1 类型的操作和函数调用之后的 struct s1 类型的操作之间排序。不幸的是,gcc 和 clang 不这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 2015-08-06
    • 2021-08-08
    相关资源
    最近更新 更多