CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 6 of 6
  1. #1
    Join Date
    Jun 2016
    Posts
    2

    Acceptable use of undefined behavior

    Hello! I'm relatively new to C++ but a long time SWE, seeking some advice on pointer casting.

    In the code below, I'm accepting some buffer (1-byte aligned) and swapping bytes as if it's an array of int16s. (Full code has equivalent methods for 32 and 64 bit types.)

    Code:
    #if defined(__GNUC__) || defined(__clang__)
    #define BSWAP_INTRINSIC_2(x) __builtin_bswap16(x)
    #elif defined(__linux__)
    #include <byteswap.h>
    #define BSWAP_INTRINSIC_2(x) bswap_16(x)
    #elif defined(_MSC_VER)
    #include <intrin.h>
    #define BSWAP_INTRINSIC_2(x) _byteswap_ushort(x);
    #else
    #define BSWAP_INTRINSIC_2(x) (x << 8) | (x >> 8)
    #endif
    
    char* data; // some char buffer
    
    // For debugging:
    int alignment = reinterpret_cast<uintptr_t>(data) % alignof(uint16_t);
    std::cout << "aligned? " << alignment << "\n";
    
    uint16_t* data16 = reinterpret_cast<uint16_t*>(data);
    
    for (size_t i = 0; i < length_of_data16; i++) {
      data16[i] = BSWAP_INTRINSIC_2(data16[i]);
    }
    Sometimes, the `data16` pointer is not 2-byte aligned. Nonetheless, all of the possible definitions of BSWAP_INTRINSIC_2 work (i.e. MSVC, g++, clang; byteswap.h's bswap_16; and the bit-shifting fall through). In the assembly I see the compilers emitting MOVDQU, so they clearly identify that this might not be aligned and they're handling it.
    1. As I understand, it's technically illegal to cast a char* to a uint16_t* without verifying alignment. Is that true?
    2. Because this code works, how bad is it to use it?
    3. Is there a way to make this legal without using memcpy/memmove/etc. (memory impact is too high for big buffers) and while still making use of the fast SSE instructions that are currently being used (e.g. PSHUFB)?


    Thanks!

  2. #2
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Acceptable use of undefined behavior

    Quote Originally Posted by zbjornson View Post
    As I understand, it's technically illegal to cast a char* to a uint16_t* without verifying alignment. Is that true?
    more precisely, it's perfectly legal to reinterpret_cast pointers of basically any type ( ignoring cv qualification ), but doing basically anything with the result ( aside casting it back to the original type provided they have proper alignment ) will give undefined behaviour

    Quote Originally Posted by zbjornson View Post
    Because this code works, how bad is it to use it?
    undefined behavoir is not "bad" per se, it just means that anything can happen ( including the program running as expected ) as far as the c++ abstract machine is concerned.

    But, if *you*/the compiler/cpu/etc... can guarantee that some operation on some specific condition has some specific behavior then you're ok and nothing 'bad' will happen.

    So, concerning your original issue, it depends on where the code will run on, consult your target compiler/cpu manual to know. AFAIR, for x86-32/64 the code should be ok at the cost of some performance penalty in the non aligned case ...

  3. #3
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Acceptable use of undefined behavior

    But, if *you*/the compiler/cpu/etc... can guarantee that some operation on some specific condition has some specific behavior then you're ok and nothing 'bad' will happen.
    but note that behaviour that is not defined as part of the standard or not documented by the compiler supplier can change between compiler releases and should be tested with every compiler change.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  4. #4
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Acceptable use of undefined behavior

    Quote Originally Posted by 2kaud View Post
    but note that behaviour that is not defined as part of the standard or not documented by the compiler supplier can change between compiler releases and should be tested with every compiler change.
    indeed, a "not documented" behaviour does not look like a "guarantee" to me

    by "guarantee" I meant things like posix/winapi multithreading in pre-c++11, platform specific ABIs etc ...

    Quote Originally Posted by zbjornson View Post
    Is there a way to make this legal without using memcpy/memmove/etc. (memory impact is too high for big buffers) and while still making use of the fast SSE instructions that are currently being used (e.g. PSHUFB)?
    BTW, I'm no SIMD expert, but given, say, a SIMD istruction operating on 16 bytes with a 2-byte UNaligned buffer, you could swap 14 bytes via that instruction and the remaining 2 bytes 'manually' ...

  5. #5
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Acceptable use of undefined behavior

    Why take a chance? Wouldn't it be better to code something using 'defined' behavior so there is a reasonable chance that it will work continue to work in the future?

  6. #6
    Join Date
    Jun 2016
    Posts
    2

    Re: Acceptable use of undefined behavior

    Thanks all. Part of me was/is hoping that this in some way is not actually making use of UB and thus that it would be safe to do, since under the hood it's only doing byte-wise operations and not really interpreting int16s.

    @superbonzo re: swapping 14 bytes on the alignment with SSE instructions and then 2 bytes, possible, although then I would have to write out the correct xmm2 (shuffle control mask) for each possible alignment and I couldn't make use of the simple built-ins. It would probably be easier to write out the assembly based on MOVDQU and PSHUFB .

    @Arjay entirely speed. It's sad to take a 6x performance hit to use defined behavior when the code works (with the three different compilers that the project is required to build with, even).

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured