Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does this really break strict-aliasing rules?

When I compile this sample code using g++, I get this warning:

warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

The code:

#include <iostream>  int main()  {    alignas(int) char data[sizeof(int)];    int *myInt = new (data) int;    *myInt = 34;     std::cout << *reinterpret_cast<int*>(data); } 

In this case, doesn't data alias an int, and therefore casting it back to an int would not violate strict aliasing rules? Or am I missing something here?

Edit: Strange, when I define data like this:

alignas(int) char* data = new char[sizeof(int)]; 

The compiler warning goes away. Does the stack allocation make a difference with strict aliasing? Does the fact that it's a char[] and not a char* mean it can't actually alias any type?

like image 522
Red Alert Avatar asked Nov 18 '14 20:11

Red Alert


People also ask

What is the strict aliasing rule and why do we care?

The compiler and optimizer are allowed to assume we follow the aliasing rules strictly, hence the term strict aliasing rule. If we attempt to access a value using a type not allowed it is classified as undefined behavior(UB).

What is C++ aliasing?

In C, C++, and some other programming languages, the term aliasing refers to a situation where two different expressions or symbols refer to the same object.

What is a type Punned pointer?

A form of pointer aliasing where two pointers and refer to the same location in memory but represent that location as different types. The compiler will treat both "puns" as unrelated pointers. Type punning has the potential to cause dependency problems for any data accessed through both pointers.


1 Answers

The warning is absolutely justified. The decayed pointer to data does not point to an object of type int, and casting it doesn't change that. See [basic.life]/7:

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:
(7.1) — [..]
(7.2) — the new object is of the same type as the original object (ignoring the top-level cv-qualifiers),

The new object is not an array of char, but an int. P0137, which formalizes the notion of pointing, adds launder:

[ Note: If these conditions are not met, a pointer to the new object can be obtained from a pointer that represents the address of its storage by calling std::launder (18.6 [support.dynamic]). — end note ]

I.e. your snippet can be corrected thusly:

std::cout << *std::launder(reinterpret_cast<int*>(data)); 

.. or just initialize a new pointer from the result of placement new, which also removes the warning.

like image 183
Columbo Avatar answered Oct 09 '22 02:10

Columbo