Search code examples
c++c++14memory-alignment

Can I use std::align to verify the alignment of a given pointer?


The following function template tries to locate an object in an array of bytes. We may assume that the argument buffer "usually" holds an object of the given type, but I need a diagnostic (assertion check) against possible errors.

template <typename T>
T* get_object_from_buffer(std::uint8_t* buffer, std::size_t size)
{
    // EDIT: This constraint was missing in original version of the question.
    if (size != sizeof(T))
    {
        // Invalid usage of the function.
        return nullptr;
    }
    
    void* tmp_buffer = buffer;
    if (nullptr != std::align( alignof(T),
                               sizeof(T),
                               tmp_buffer,
                               size ) )
    {
        return reinterpret_cast<T*>(buffer);
    }
    else
    {
        // Caller can check returned pointer to implement diagnostic reactions
        return nullptr;
    }
}

Questions:

  1. Is it allowed (and portable) to do this using std::align?

  2. Do you see a better solution - more robust, more elegant?

Conditions:

  • The function will be used on an embedded system. Hence, some google hits for std::align usage on PC platforms are not applicable.

  • Buffer is filled by a function like the following:

        template <typename T>
        std::pair<std::uint8_t*, std::size_t> put_object_into_buffer(T* object)
        {
            return std::pair<std::uint8_t*, std::size_t>(
                            reinterpret_cast<std::uint8_t*>(object),
                            sizeof(object)
                        );
        }
    

    Between the put/get functions, I have to pass the buffer through a library that is not aware of user-defined types like T.


Edit/Update: The buffer representation of uint8_t* and size_t is only meant to hold a single T object. This was missing in the original question post. I have added the check that the size argument actually matches the size of the object.

Without this check, std::align() can easily locate an aligned T* in buffer so that the criterion is not relevant any more. Thanks to Ted Lyngmo for pointing this out!


Solution

  • Answer motivated by comments of @Ted Lyngmo - see comments to question

    • The check against size == sizeof(T) is essential.

      Otherwise, std::align() will not return nullptr whenever the size beyond a misaligned buffer pointer allows to place an entire, aligned T instance somewhere between &(buffer[0]) and &(buffer[size-1]).

    • Using the nullptr function return value for error cases, it is not necessary to distinguish between buffer and tmp_buffer if the return value is a type cast of std::align().

      Then, the function can be shortened:

      template <typename T>
      T* get_object_from_buffer(std::uint8_t* buffer, std::size_t size)
      {
          if (size != sizeof(T))
          {
              // Invalid usage of the function.
              // Caller shall check returned pointer to implement diagnostic reactions
              return nullptr;
          }
          else
          {
              void* tmp_buffer = buffer;
              return reinterpret_cast<T*>(std::align(alignof(T), sizeof(T), tmp_buffer, size));
          }
      }
      

      or even

       template <typename T>
       T* get_object_from_buffer(std::uint8_t* buffer, std::size_t size)
       {
           void* tmp_buffer = buffer;
      
           // Caller shall check returned pointer against 'nullptr' to implement diagnostic reactions
           return reinterpret_cast<T*>(
                   size == sizeof(T)
                       ? std::align(alignof(T), sizeof(T), tmp_buffer, size) 
                       : nullptr);
       }