Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implicit Type Conversion of Array Index Values in ARM-C

Tech 2

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 to r0 = 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.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.