cmemorycastinghardwarebuffer-overrun

Typecasting Arrays for Variable Width Access


Sorry, I am not sure if I wrote the title accurately.

But first, here are my constraints:

  1. Array[], used as a register map, is declared as an unsigned 8-bit array (uint8_t), this is so that indexing(offset) is per byte.
  2. Data to be read/written into the array has varying width (8-bit, 16-bit, 32-bit and 64-bit).
  3. Very Limited Memory and Speed is a must.

What are the caveats in doing the following

uint8_t some_function(uint16_t offset_addr) //16bit address
{
  uint8_t Array[0x100];
  uint8_t data_byte = 0xAA;
  uint16_t data_word;
  uint32_t data_double = 0xBEEFFACE;

\\ A. Storing wider-data into the array
*((uint32_t *) &Array[offset_addr]) = data_double;

\\ B. Reading multiple-bytes from the array
data_word = *((uint16_t *) &Array[offset_addr]);
 
  return 0;
}

I know i could try writing the data per byte, but that would be slow due to bit shifting.

Is there going to be a significant problem with this usage? I have run this on my hardware and have not seen any problems so far, but I want to take note of potential problems this implementation might cause.


Solution

  • Is there going to be a significant problem with this usage?

    It produces undefined behavior. Therefore, even if in practice that manifests as you intend on your current C implementation, hardware, program, and data, you might find that it breaks unexpectedly when something (anything) changes.

    Even if the compiler implements the cast and dereference in the obvious way (which it is not obligated to do, because UB) misaligned accesses resulting from your approach will at least slow many CPUs, and will produce traps on some.

    The standard-conforming way to do what you want is this:

    uint8_t some_function(uint16_t offset_addr) {
      uint8_t Array[0x100];
      uint8_t data_byte = 0xAA;
      uint16_t data_word;
      uint32_t data_double = 0xBEEFFACE;
    
    \\ A. Storing wider-data into the array
      memcpy(Array + offset_addr, &data_double, sizeof data_double);
    
    \\ B. Reading multiple-bytes from the array
      memcpy(&data_word, Array + offset_addr, sizeof data_word);
     
      return 0;
    }
    

    This is not necessarily any slower than your version, and it has defined behavior as long as you do not overrun the bounds of your array.