Implicit Type Conversion of Array Index Values in ARM-C
Problem Description
A program implements a circular buffer using a 256-element array with byte-type data as an index, leveraging the overflow behavior where values wrap around to zero:
#include "stdint.h"
int main()
{
uint8_t index = 0;
uint16_t array[256] = { 0 };
while(1) {
array[index++] = index; // Store index in array
}
}
For debugging purposes, an additional larger array was introduced to store more data for breakpoint inspection:
#include "stdint.h"
#define DEBUG
int main()
{
uint8_t idx = 0;
uint16_t buffer[256] = { 0 };
while(1) {
buffer[idx++] = idx; // Store index in buffer
#ifdef DEBUG
static uint16_t debug_buffer[2048] = { 0 };
static uint16_t debug_idx = 0;
debug_buffer[debug_idx++] = buffer[idx - 1];
if(debug_idx == 2047)
debug_idx = 0; // Breakpoint here to capture last 2048 data points
#endif
}
}
During debugging, it was observed that elements at positions 256, 512 (multiples of buffer size) did not match expectations.
Root Cause Analysis
Why does debug_buffer[debug_idx++] = buffer[idx - 1] produce unexpected results? Let's examine the disassembly code:
The assembly shows:
SUBS r0,r4,#1: Subtracts 1 from the value in register r4 (holding idx) and stores result in r0- When
idx=0, r0 contains 0xFFFFFFFF (32-bit representation) LDRH r1,[sp,r0,LSL #1]: Loads halfword from adress calculated as sp + (r0 << 1)
Since buffer is a 16-bit array, each element occupies 2 bytes, so the address calculation becomes: &buffer[idx-1] = buffer + 2 * (idx-1)
The problem occurs when r0 contains 0xFFFFFFFF. Left-shifting by 1 bit produces 0xFFFFFFFE, effectively accessing buffer + 0xFFFFFFFE instead of the intended location.
Solution
Force explicit type conversion of the array index. Note that casting only the index variable before subtraction is ineffective!
Incorrect approach:
// This doesn't work!
debug_buffer[debug_idx++] = buffer[(uint8_t)idx - 1];
Correct approach:
// Proper casting after arithmetic
debug_buffer[debug_idx++] = buffer[(uint8_t)(idx - 1)];
After applying the fix, the disassembly shows UXTB r0, r0 instruction inserted between the subtraction and load operations:
UXTB r0, r0: Zero-extends the byte value, equivalent tor0 = r0 & 0xff
With this correction, the output behaves correctly.
This demonstrates that array indices undergo implicit type conversion during evaluation, making it dangerous to use variables directly as indices without careful consideration of type behavior.