martinmoene / byte-lite

byte lite - A C++17-like byte type for C++98, C++11 and later in a single-file header-only library
Boost Software License 1.0
53 stars 8 forks source link

Failure on big-endian architecture #10

Closed jpcima closed 2 years ago

jpcima commented 2 years ago

Hi, byte-lite appears to fail the tests in a big-endian configuration. For context, it was an automated build having the s390x architecture enabled.

/builddir/build/BUILD/byte-lite-0.3.0/test/byte.t.cpp:193: failed:
byte: Allows strict aliasing: 14 == F::f( i, reinterpret_cast<nonstd::byte&>( i ) ) for 14 == 7

builder-live.log.gz

martinmoene commented 2 years ago

Thanks @jpcima, the particular test is endian-dependent and wrong for big-endian configurations.

CASE( "byte: Allows strict aliasing" )
{
    struct F {
        static int f( int & i, nonstd::byte & r )
        {
           i = 7;
           r <<= 1;
           return i;
        }
    };

   int i;
   EXPECT( 14 == F::f( i, reinterpret_cast<nonstd::byte&>( i ) ) );
}

Pondering how to make it endian-independent...

jpcima commented 2 years ago

Thanks @martinmoene. It would appear however that this modification still hasn't fixed the problem.

1/4 Test #1: test-cpp98 .......................***Failed    0.00 sec
/builddir/build/BUILD/byte-lite-0.3.0/test/byte.t.cpp:207: failed: byte: Allows strict aliasing: (r == 0x0E || 0x0E00 == r) for false
1 out of 19 selected tests failed.
martinmoene commented 2 years ago

mmm, thanks @jpcima

Do you have 1) an idea what would be a good approach for the test, preferably without determining the system's endianness? 2) a hint for online testing with a big endian configuration? 3) entirely different suggestions?

Thanks if you do.

jpcima commented 2 years ago

The following runs with success. What do you think about it?

CASE( "byte: Allows strict aliasing" )
{
    struct F {
        static int f( int & i, nonstd::byte & r )
        {
           r <<= 1;
           return i;
        }
    };

   int i = 7;

   unsigned char& first = reinterpret_cast<unsigned char&>( i );
   unsigned char& last = *( reinterpret_cast<unsigned char*>( &i ) + sizeof(int) - 1 );

   bool little = ( first == 7 ) && ( last == 0 );
   bool big = ( first == 0 ) && ( last == 7 );
   EXPECT( (little ^ big) );
   unsigned char& lsb = little ? first : last;

   EXPECT( 14 == F::f( i, reinterpret_cast<nonstd::byte&>( lsb ) ) );
}
martinmoene commented 2 years ago

Ah, thank you :)