简体   繁体   中英

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.

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.

This is probably fine. Many have done things like this. C performs well with this kind of thing.

Two things to watch out for:

  1. Buffer overruns. You know those zero-days like Eternal Blue and hacks like WannaCry? Many of them exploited bugs in code like yours. Malicious input caused the code to write too much stuff into data structures like your uint8_t Array[0x100] . Be careful. Avoid allocating buffers on the stack (as function-local variables) as you have done because clobbering the stack is exploitable. Make them big enough. Check that you don't overrun them.

  2. Machine byte ordering vs. network byte ordering, aka endianness . If these data structures move from machine to machine over the net you may get into trouble.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM