5

I have a structure which aims at storing user defined data (i.e. from a plugin). It has a such a char[] with a given maximum size to store that data.

struct A
{
    // other members omitted
    // data meant to be type punned, only contains PODs
    char data[256];
};

Then there's a sample user structure that has a static function to cast itself from A.

struct B
{
    int i;
    double d;

    static B& FromA_ref(A& a)
    {
        // static_assert that sizeof(B) < sizeof(A::data)
        return * reinterpret_cast<B*>(a.data);
    }
};

I compile with g++ -O3 -std=c++0x -Wall -o test test.cpp (GCC 4.6.1).

This triggers a dereferencing type-punned pointer will break strict-aliasing rules warning. I thought that would be ok since I have used a char[] as storage which I thought would follow the same rules as char*. I find it strange that it doesn't. Don't you ? Well, ... I can't change it right now, so let's move on.

Now let's consider the following method:

struct B
{
    ....
    static B* FromA_ptr(A& a)
    {
        // static_assert that sizeof(B) < sizeof(A::data)
        return reinterpret_cast<B*>(a.data);
    }
}

Since I am not dereferencing anything here GCC doesn't output any warning. Neither does it when I use my pointer to B later on.

A a;
auto b = B::FromA_ptr(a);
b->i = 2; // no warnings.

But is it safe to do so ? I feel like I have been working my way around the problem rather than solving it. For me -> is still dereferencing the variable somehow.

Alternatively, are there any better way to achieve the effect ? I.E. get a modifiable reference (or pointer) casted from a storage inside another struct ? (Union won't work since the set of types stored are not known when A is defined and some may be added via plug-ins, memcpy will force me to copy the data back and forth though it seems to be the only safe way so far)

J.N.
  • 8,203
  • 3
  • 29
  • 39
  • I'm no expert, but are you looking for the `__may_alias__` attribute? http://blog.worldofcoding.com/2010/02/solving-gcc-44-strict-aliasing-problems.html – Russell Borogove Apr 03 '12 at 01:14
  • Anyway, how do you deal with the alignment issue? – curiousguy Jul 11 '12 at 07:12
  • @curiousguy : so far I don't but I should. On x86 I guess that I may degrade the performance at worst, though. I hope `__attribute__((aligned(8)));` would be enough since I am not trying to auto vectorize anything. Probably, `may_alias` already tells GCC to pay attention to alignment before doing too much weird stuff. – J.N. Jul 12 '12 at 06:21
  • 1
    @curiousguy: A simple approach should be `union { char dat[theSize]; typeWithWorstAlignment dummy; }`. That would take care of everything but aliasing issues, for which the Standard offers no solution. Given the lack of any solution to aliasing issues, I find it odd that the C11 Standard included alignment directives which aren't really useful *except* in circumstances involving type punning. – supercat Feb 13 '17 at 17:22

1 Answers1

4

The answer is no, it is not safe (see this SO question)

GCC will assume that the pointers cannot alias. For instance, if you assign through one then read from the other, GCC may, as an optimisation, reorder the read and write - I have seen this happen in production code, it is not pleasant to debug.

attribute((may_alias)) on the types used is probably the closest you can get to disabling the assumption for a particular section of code.

Community
  • 1
  • 1
Attila
  • 28,265
  • 3
  • 46
  • 55