2

I know that int* ptr = (int*)buffer (where buffer is char*) breaks strict-aliasing rule.

Does this syntax int& ref = (int&)(*buffer) also break the rule?

I had some SEGFAULTs due to violation of the strict aliasing rule, and this syntax has eliminated that. Though probably still is incorrect, is it?

Community
  • 1
  • 1
mambo_sun
  • 509
  • 4
  • 13

3 Answers3

3

This is not ok (assuming you're going to use said reference to access the value). § 3.10 [basic.lval] ¶ 10 of the C++14 standard (quoting N4140) says (emphasis mine):

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

  • the dynamic type of the object,
  • a cv-qualified version of the dynamic type of the object,
  • a type similar (as defined in 4.4) to the dynamic type of the object,
  • a type that is the signed or unsigned type corresponding to the dynamic type of the object,
  • a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
  • an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),
  • a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
  • a char or unsigned char type.

It doesn't matter whether you attempt to access via a pointer or a reference. For a stored object of type char, none of the bullet points apply to make it allowed accessing it as an int.

The last bullet point only says that you may alias any other type as char but not vice versa. It makes sense because a char is the smallest addressable unit with the weakest alignment requirements.

If you want, using a pointer is the same as using a reference except that you need to dereference explicitly in order to access the value.

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
2

Strict aliasing rules mean that you should not dereference pointers of different types pointing to the same memory location.

Since in your posted code you never dereference, it's not possible to tell if this violates the rule without seeing all the code.

Also, aliasing to the char* type is an exception and does not violate the rule. Which means you can access a memory location containing any type by converting its pointer to char*, and dereferencing it.

To conclude:

  • If buffer points on a memory location which contains an int, and was converted from int* to char*, this is valid. However, you should use reinterpret_cast for this
  • If buffer points to a memory location which contains chars, dereferencing the int* ptr does violate the rule.
  • The reference version is likely to suffer from the same problem. But the compiler has no obligation to prevent or warn you from doing this
  • Don't use C style casts, use reinterpret_cast instead, and read the standard about which uses have defined behavior.
galinette
  • 8,896
  • 2
  • 36
  • 87
  • As I understood from reading on the matter, aliasing T* with char* is allowed, but the other way around is not. For example [here](http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) they say so. "However this won't work the other way: there's no assumption that your struct aliases a buffer of chars". Also for example [here](http://stackoverflow.com/questions/32831329/strict-aliasing-and-writing-int-via-char) they say, that `*((*int)p) = value;` violates strict aliasing – mambo_sun Nov 21 '15 at 23:12
  • Except if you convert int* to char* , then back to int*. This is perfectly allowed and in that case, you are effectively converting a char* to int* and dereferencing it somewhere in your code. – galinette Nov 21 '15 at 23:20
2

Yes, it does.

Neither C nor C++ special case accesses via pointers vs. other accesses, the strict aliasing rules apply regardless of whether you use a pointer, a reference, or any other lvalue.

If you run into trouble, the easiest solution is to use memcpy to copy the memory location into a local variable - any self-respectable compiler will completely optimise this memcpy away and only treat it as an aliasing hint (memcpy is also preferable over unions, because the union method is not as portable).

Remember Monica
  • 3,897
  • 1
  • 24
  • 31
  • Do you recommend the `memcpy` for both C and C++? – curiousguy Jun 11 '18 at 01:23
  • I'm not recommending it, nor the opposite, I merely point this out as an easy and correct method. There are alternatives, for example, unions work, although some compilers in the past weren't sure about this, as would manual char-by-char copying or equivalent methods. memcpy will always work, though, and is often as efficient or more efficient than other methods. – Remember Monica Jul 27 '18 at 02:40
  • Does anything in either the C or C++ Standard actually specify that the use of an lvalue of the form `aggregate.member` to access a member of non-character type is not considered a violation of N1570 6.5p7 (C) or N4140 3.10p10 (C++), or do the Standards treat that as a Quality of Implementation issue (recognizing that whether or not the Standard requires implementations to behave usefully when code accesses aggregate members, only a really horrid implementation would fail to do so)? – supercat Jul 31 '18 at 21:47