Skip to main content

Debugging Memory Overwrite Issues in Embedded C

·601 words·3 mins
C Embedded Memory Debugging
Table of Contents

Introduction
#

Memory bugs in C are notoriously tricky. Locating the issue is often much harder than fixing it. One of the most common and dangerous problems is memory overwrite—when code unintentionally writes beyond its allocated region, corrupting adjacent memory.

Such overwrites may cause anything from subtle functional errors to full program crashes. In embedded systems, these bugs can be catastrophic.

Let’s explore how overwrites can occur in static and dynamic storage areas, and techniques to detect them.


Static Memory Overwrite
#

Example: Array Out-of-Bounds
#

In Linux, a process can typically open up to 1024 file descriptors (0–1023). In one project, we noticed a UART file descriptor (fd) suddenly holding an invalid value. Debugging revealed that it had been overwritten due to an array out-of-bounds bug:

float arr[5];
int count = 8;
for (size_t i = 0; i < count; i++) {
    arr[i] = xxx;
}

Since count exceeds the array size, memory beyond arr was overwritten, corrupting other variables, including fd.

Locating the Bug with a Map File
#

In Linux, simply logging values won’t reveal which adjacent variable is being corrupted. A more systematic approach is to generate a map file to see variable placements:

set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=output.map")  # generate map file
set(CMAKE_C_FLAGS "-fdata-sections")               # output static variable addresses
set(CMAKE_CXX_FLAGS "-fdata-sections")

This allows you to trace which variables are next to each other in memory.


Dynamic Memory Overwrite
#

Dynamic memory overwrites are equally common. A classic case is improper use of malloc and strcpy:

char *str = "hello";
int str_len = strlen(str);   // str_len = 5

char *ptr = (char *)malloc(str_len);  // only 5 bytes allocated
char *p_a = ptr + 5;
*p_a = 20;  // writing beyond allocated space

strcpy(ptr, str);  // overwrites adjacent memory

Output shows *p_a being unexpectedly modified after strcpy—a silent corruption caused by ignoring the null terminator (\0), which requires 1 extra byte.


Detecting Memory Overwrites
#

When overwrites occur, they may or may not cause immediate crashes, depending on what data is stored nearby. This makes them difficult to reproduce.

Tools You Can Use
#

  • dmalloc
  • valgrind

These runtime tools can help detect illegal memory accesses.


Custom Detection with “Red Zones”
#

Another technique is to implement red zones—guard regions around allocated memory.

  • Before Red Zone: 4 bytes, fixed value 0x11223344
  • After Red Zone: 4 bytes, fixed value 0x55667788
  • Length Area: 4 bytes, stores allocated length

This way, you can detect if the memory immediately before or after your allocated region has been corrupted.

Custom Malloc
#

void *Malloc(size_t __size) {
    void *ptr = malloc(4 + 4 + __size + 4); // before + len + data + after
    if (!ptr) return NULL;

    *((unsigned int*)(ptr)) = 0x11223344;             // before red zone
    *((unsigned int*)(ptr + 4)) = __size;             // length
    *((unsigned int*)(ptr + 8 + __size)) = 0x55667788; // after red zone

    return ptr + 8;  // return data area
}

Memory Check
#

void CheckMem(void *data_ptr, size_t __size) {
    assert(*((unsigned int*)(data_ptr - 8)) == 0x11223344);   // before
    assert(*((unsigned int*)(data_ptr - 4)) == __size);       // length
    assert(*((unsigned int*)(data_ptr + __size)) == 0x55667788); // after
}

If an overwrite occurs, the red zone will be corrupted, and the assertion will immediately trigger.


Conclusion
#

Memory overwrite issues in Embedded C are subtle, dangerous, and often difficult to track down.

  • Static overwrites often result from array out-of-bounds.
  • Dynamic overwrites frequently stem from incorrect allocation sizes or unsafe functions like strcpy.
  • Detection techniques include using tools like Valgrind, or custom guard zones with assertions.

👉 By combining systematic debugging with protective coding strategies, you can detect these issues early—before they turn into elusive and costly bugs.

Related

C File I/O Tutorial with Examples: fopen, fclose, fread, fwrite
·664 words·4 mins
C File Linux
Mastering assert in C Language: Usage and Best Practices
·554 words·3 mins
C Language Assert Debugging Best Practices
C语言必备知识枚举
·179 words·1 min
程序 C Enum