dereferencing type-punned pointer will break strict-aliasing rules

最近遇到了一个编译告警,严格别名和类型双关,整理一下相关的材料。

strict aliasing

以下问题摘自1
在这里插入图片描述
I have the following questions:

  1. If I leave the code with this warning, will it generate potentially wrong code?
  2. Is there any way to work around this problem?
  3. If there isn’t, is it possible to turn off strict aliasing from inside the source file (because I don’t want to turn it off for all source files and I don’t want to make a separate Makefile rule for this source file)?
    And yes, I actually need this kind of aliasing.

The strict aliasing rule makes this setup illegal, two unrelated types can’t point to the same memory. char * are defined as being able to alias anything, only char* / unsigned char* has this privilege.

aliasing assumptions

这个告警只有在 strict aliasing optimization 开启的情况下才会出现,gcc-O2 优化会开启上述优化2,因此会出现该告警,忽略该告警有可能产生错误代码。出现该告警的原因是编译器为了优化代码,做了一个假设,即指针不会有其他类型的别名, (char *) 例外,意思是两个类型不同的指针不会指向同一块内存。当然这个特性孰好孰坏我们这里暂不讨论,实际上争议还是比较大的3

Aliasing rules simply say that you can only access an object through its own type, its signed / unsigned variant type, or through a character type (signed char, unsigned char).

如何解决

如题主所问,如果我们确实需要做指针强制类型转换,怎样才能解决这个告警并得到健壮的代码呢?
C/C++ 是非常贴近硬件底层的语言,指针为我们编程提供了很大的便利性,同时也引入了一些隐患。我们可以很方便地重新解析一块内存上的数据(reinterpret) ,隐患是相伴便利性而生的,有时指针类型强转并不安全,例如出现未初始化字节数据的问题。

我们可以采用以下做法来消除这个告警:

  • 采用 __attribute__((__may_alias__)) 属性去提示编译器对某个变量关闭上面提到的假设。
  • 关闭这个假设, -fno-strict-aliasing,可能影响优化,linux kernel 有大量的指针操作,其构建带这个选项。
  • 屏蔽这个告警,-Wno-strict-aliasing,很不推荐!有掩耳盗铃之嫌!
  • 使用 union 来解决,这也是 gcc 推荐的做法。type punning via unions feels natural
int retLen;
someSetFunc((unsigned long*)&retLen);
printf("ret len = %d\n", retLen);

...

union u_retLen {
	int retLen;
	unsigned long ptr;
};
someSetFunc(&u_retLen.ptr);
printf("ret len = %d\n", u_retLen.retLen);

  1. https://stackoverflow.com/questions/4163126/dereferencing-type-punned-pointer-will-break-strict-aliasing-rules-warning/4163223 ↩︎

  2. https://gcc.gnu.org/onlinedocs/gcc-7.5.0/gcc/Optimize-Options.html#Optimize-Options ↩︎

  3. https://lkml.org/lkml/2018/6/5/769 ↩︎

### 回答1: dereferencing type-punned pointer是指对一个类型转换后的指针进行解引用操作。这种操作可能会导致未定义的行为,因为不同类型的指针可能具有不同的内存布局和对齐方式,解引用操作可能会访问到错误的内存位置,导致程序崩溃或产生不可预测的结果。因此,应该避免使用这种类型的指针操作。 ### 回答2: dereferencing type-punned pointer(解引用类型转换指针) 首先需要了解的是类型转换指针,它是一个指针,它可以将一个变量解释为不同类型的变量。例如,一个int型指针可以转换为一个char型指针,它可以让程序员通过不同类型查看同一块内存区域,但是这个过程是非常危险的,尤其是在解引用指针时,很容易引发问题。 当我们使用一个指针解引用时,我们希望得到的是一个合法的内存地址,即指向有效的对象的指针。但是如果我们使用一个类型转换指针,则不一定能够保证指针指向的内存区域是有效的。这种情况可能导致非法的内存访问、程序崩溃,并可能导致安全漏洞。例如,以下代码使用了一个类型转换指针: ``` int a = 10; float b = *(float*)&a; ``` 这个代码段将一个整数a的地址解释为一个浮点数b的地址,并通过解引用类型转换指针来获取浮点数的值。如果a的内存区域不足以容纳一个浮点数,或者已经被释放了,那么这个代码就会引起问题。 解决这个问题的方法是使用正确的类型来解引用指针,或者使用内存操作函数来完成转换。例如,在上面的例子中,我们可以使用以下代码来完成类型转换: ``` int a = 10; float b; memcpy(&b, &a, sizeof(float)); ``` 这个代码使用了memcpy函数将一个整数a的地址复制到一个float类型的变量b中。这种方法可以保证我们不会出现类型转换指针导致的问题。 ### 回答3: dereferencing type-punned poin是指对通过类型转换得到指针的解引用操作。在C/C++中,类型转换是一种常见的操作,有时候我们需要将一个指针“重新解释”为另外一个指针类型,通过这种方式访问不同类型的数据。但是,这种做法实际上是非法的,可能会引起严重的后果。 具体来说,dereferencing type-punned poin可能会导致以下几个问题: 1.非法内存访问。由于类型转换后,指针所指向的数据类型发生了变化,新的数据类型可能会导致访问非法内存。 2.未定义的行为。C/C++标准中有很多规则限制了指针类型转换的行为,如果不遵守这些规则,可能会导致未定义的行为。 3.平台依赖性。某些类型转换可能会涉及平台依赖性,例如对指针进行位操作,这种做法可能会依赖于底层硬件的字节序等因素。 因此,避免dereferencing type-punned poin非常重要。如果确实需要进行类型转换,建议使用标准库中提供的转换函数,而不是手动进行位操作等操作。另外,在使用指针类型转换时,也要充分了解C/C++标准中的规则,以避免不必要的安全问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值