1

About the example below, in f1, no alias occurs because p(void*) isn't accessible and p1 is the only pointer accessing memory. However, there is a pointer aliasing between p1(float*) and p2(int*) which is outside f1.
My question is that, is this alias illegal or not, that is, does the strict-aliasing rules apply across function calls ?

If this example is valid, what if the f1 is inlined ?

void f1(void *p)
{
  auto* p1 = static_cast<float*>(p);
  *p1 = 1.f;
}

int f2()
{
  int x = 1;
  auto* p2 = &x;
  f1(&x);
  *p2 = 1;
  return *p2;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
wanwan
  • 93
  • 10
  • 1
    "what if the f1 is inlined" - inlining does not have any impact on the strict aliasing rule AFAIK. The code always needs to be correct regarding aliasing, irrespective of whether the compiler chooses to inline or not. – Jesper Juhl Apr 15 '19 at 13:39
  • 2
    Whether this violates strict aliasing or not; another consideration: Does this violate object lifetime? Does there exist an object of type `float` at `*p1` when that object is being assigned? – eerorika Apr 15 '19 at 13:45
  • 1
    `memcpy` has special privileges and gets optimized away, so use it instead of `static_cast` to get at the bits. – Filipp Apr 15 '19 at 16:24
  • @eerorika I you assume an object is created by assignment (as it should be), that object has nothing to do with any other incompatible object type that used to reside here. Would other pointers be invalidated? – curiousguy Apr 26 '19 at 16:59
  • @curiousguy Can you assume that an object *is created by assignment*? [This post](https://stackoverflow.com/a/40874245/2079303) disagrees. *An object is created by a definition ([basic.def]), by a new-expression ([expr.new]), when implicitly changing the active member of a union ([class.union]), or when a temporary object is created ([conv.rval], [class.temporary]).* – eerorika Apr 26 '19 at 17:14
  • @eerorika Yes the text you quoted is patent BS. Also if you trust that section, do you believe that any use of union was UB in previous C++ versions? – curiousguy Apr 26 '19 at 17:15
  • @curiousguy If you don't like the standard, then I suggest you propose to change it. Not *any* use of union is UB. But type punning and array aliasing tricks using union were UB according to the standard. Are you suggesting that they are no longer? – eerorika Apr 26 '19 at 17:25
  • @eerorika If you take the std seriously, you have several things; literal strings have no lifetime and don't exist; ptr are trivial types, which means any identity function implements `launder` which is never needed despite the std saying it is needed; relaxed atomics can see values from the future which means they could see UB from the future meaning that UB could just cause UB... the std is full of holes, contradictions... many ppl have noticed already. – curiousguy Apr 26 '19 at 17:33

2 Answers2

8

It doesn't matter how many times you copy a pointer or pass it to somewhere else or how many times you convert it, the determining factor is always what's actually stored at that location.

In your case, the only thing that matters is whether static_cast's argument actually is the address of a float, and it isn't.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • 3
    To be more precise, the only thing that matters is whether `*p1` actually refers to an object of type `float`. It doesn't, therefore UB. This just to clarify that the problem is not the `static_cast` itself but the access to the stored value of an object through an lvalue of [the wrong type](http://eel.is/c++draft/basic.lval#11)… – Michael Kenzel Apr 15 '19 at 13:44
  • I see... In this case, the type of the stored value is `int` and `f1` tries to access it as `float` and this never change no matter how many function calls or type conversions there are, so this inconsistency causes an UB... Thank you for a concise explanation. – wanwan Apr 15 '19 at 17:52
0

Compilers that are suitable for low-level programming on platforms with a published ABI will provide a means of forcing function calls to be performed in a fashion consistent with that ABI, which would in turn force "strict aliasing violations" that cross the function-call boundary to be handled "in a documented fashion characteristic of the environment". Such support is a "popular extension" which the authors of the Standard regard as outside their jurisdiction. Compilers that are designed and configured to be suitable for low-level programming will support such constructs without regard for whether the Standard requires it, and those which aren't designed and configured to be suitable for such purposes shouldn't be used for them.

supercat
  • 77,689
  • 9
  • 166
  • 211