Code to run alias errors reliably?

The name pretty much says it all. Can someone direct me or provide me with code that will reliably trigger alias errors with several recent gcc versions? The reason I ask is because I'm trying to learn the effects of a strict alias, but no matter how hard I try to break it, gcc always comes up with the “right” result, doing some kind of test on how to deal with situations where you want to break the rules are pretty much worthless. I'm not asking for warnings (-Wstrict-aliasing = 2 gives warnings in almost everything I do), but code that actually doesn't work when optimizing with -fstrict-aliasing.

#include <stdio.h>
#include <stdint.h>

typedef struct mystruct_s {
    uint32_t int1;
    uint32_t int2;
} mystruct_t;

typedef mystruct_t __attribute__( ( may_alias ) ) mystruct_alias_bad1_t;
// warning: ignoring attributes applied to ‘struct mystruct_s’ after definition [-Wattributes]
// so basically gcc is telling me i have to define it again if want an aliasable
// version?

typedef struct mystruct_alias_s {
    uint32_t int1;
    uint32_t int2;
} __attribute__( ( may_alias ) ) mystruct_alias_t;

static __attribute__( ( optimize( "no-strict-aliasing" ) ) ) void myfunc1_alias1( void ) {
    uint32_t var, *i = &var;
    float *f = (float*)&var;
    // warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
    // so __attribute__( ( optimize( "no-strict-aliasing" ) ) ) is either
    // not doing anything or gcc still gives warning even if the
    // optimization does not actually happen 

    *i = 100;
    printf( "[test-5] %u", var );
    *f = 0.f;
    printf( " %u (%s)\n", var, var != 100 ? "OK" : "FAIL" );
}

#pragma GCC optimize "no-strict-aliasing"
static void myfunc1_alias2( void ) {
    uint32_t var, *i = &var;
    float *f = (float*)&var;
    // warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
    // this seems to be identical to the 
    // __attribute__( ( optimize( "no-strict-aliasing" ) ) ) case

    *i = 100;
    printf( "[test-6] %u", var );
    *f = 0.f;
    printf( " %u (%s)\n", var, var != 100 ? "OK" : "FAIL" );
}
#pragma GCC optimize "strict-aliasing"

static void myfunc1( void ) {
    uint32_t var, *i = &var;
    float *f = (float*)&var;
    // warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
    // conclusion: pretty much none. all 3 functions generate exatcly the same
    // code that does just work as expected with no breakage at all despite the
    // warning so no-strict-aliasing on a per function level might do nothing
    // at all or just not for this code - no way to really tell...

    *i = 100;
    printf( "[test-7] %u", var );
    *f = 0.f;
    printf( " %u (%s)\n", var, var != 100 ? "OK" : "FAIL" );
}

int main( int argc, char **argv ) {
    unsigned char buf[sizeof( mystruct_t )] = { 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02 };

    // obvious rule violation:
    printf( "[test-1] int2 == %08X\n",
        ( (mystruct_t*)buf )->int2
        // warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
    );
    // prints: [test-1] int2 == 2020202

    // pretty much the same as above but avoiding the struct:
    printf( "[test-2] int1 == %08X, int2 == %08X\n",
        *(uint32_t*)buf,
        // warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
        ( (uint32_t*)buf )[1]
        // warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
        // (you need -Wstrict-aliasing=2 - just -Wstrict-aliasing is not enough)
    );
    // prints: [test-2] int1 == 1010101, int2 == 2020202

    // lets try telling gcc that it should respect what we are trying to do:
    printf( "[test-3] int1 == %08X, int2 == %08X\n",
        ( ( __attribute__( ( may_alias ) ) mystruct_t*)buf )->int1,
        // warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
        ( (mystruct_alias_t*)buf )->int2
        // this is the only one that works so far but it seems there is no way
        // to cast to such a pointer on the fly - you have to apply this
        // attribute to the original struct...
    );
    // prints: [test-3] int1 == 1010101, int2 == 2020202

    // lets try to be creative (basically make a mess with C99 anonymous arrays):
    printf( "[test-4] int1 == %08X, int2 == %08X\n",
        ( (  __attribute__( ( may_alias ) ) mystruct_t* [1] ) { (mystruct_t*)buf } )[0]->int1,
        // warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
        // (you need -Wstrict-aliasing=2 - just -Wstrict-aliasing is not enough)
        // seems the attribute is ignored just as silently as for the direct cast
        ( ( mystruct_t* [1] ) { (mystruct_t*)buf } )[0]->int2
        // warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
        // (you need -Wstrict-aliasing=2 - just -Wstrict-aliasing is not enough)
        // i guess that evades -Wstrict-aliasing since that seems to pretty
        // much seems to only warn about code that casts and dereferences in one
        // go
    );
    // prints: [test-4] int1 == 1010101, int2 == 2020202

    // lets try to use __attribute__ optimize to disable strict aliasing temporaly:
    myfunc1_alias1();

    // lets try pragma:
    // #pragma GCC optimize "-fno-strict-aliasing"
    // error: #pragma GCC optimize is not allowed inside functions
    // (at least if you uncomment that line) so lets try a function again:
    myfunc1_alias2();

    // lets check if compiling the function without any makeup makes a difference:
    myfunc1();

    return 0;
}

Final editing:

, mnunberg :

__attribute__( ( may_alias ) )

, (, , ) - .

__attribute__( ( optimize( "no-strict-aliasing" ) ) )

, . .

#pragma GCC optimize "no-strict-aliasing"

, , , ().

+4
1

, , GCC. GCC , bp->a :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char *a;
    char *b;
} s_v;
typedef struct {
    char *a;
    char *b;
} s_b;

static inline void do_foo(s_v *buf, s_b *bp)
{
    buf->a = (char*)0x010;
    buf->b = (char*)0x020;
    bp->a = buf->a;
    bp->b = buf->b;
    while (bp->a) {
        buf->a--;
    }
}

int main(void)
{
    s_v *buf = malloc(sizeof (s_v));
    s_b *bp = (s_b*)buf;
    do_foo(buf, bp);
    return 0;
}

(objdump)

  4003c0:   eb fe                   jmp    4003c0 <main>
  4003c2:   90                      nop
  4003c3:   90                      nop

GCC:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.7/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.7.3-4' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --with-system-zlib --enable-objc-gc --with-cloog --enable-cloog-backend=ppl --disable-cloog-version-check --disable-ppl-version-check --enable-multiarch --with-arch-32=i586 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.7.3 (Debian 4.7.3-4) 
+1

Source: https://habr.com/ru/post/1540964/


All Articles