Essential Tools for Embedded Development: Sanitizer

Hello everyone, I am the Mixed Cuisine Master. Today we are going to share a development and debugging tool – Sanitizer.

Introduction to Sanitizer

Sanitizer is an open-source toolkit initiated by Google, designed to detect memory leaks and other issues.

Link: https://github.com/google/sanitizers/wiki/

It includes various tools such as AddressSanitizer, MemorySanitizer, ThreadSanitizer, and LeakSanitizer. These tools were originally part of the LLVM project and later supported by the GNU GCC compiler. Since version 4.8 of GCC, AddressSanitizer and ThreadSanitizer have been supported, while version 4.9 started supporting LeakSanitizer.

Essential Tools for Embedded Development: Sanitizer

Usage of Sanitizer

1. Example of Using AddressSanitizer

AddressSanitizer (ASan) is a fast memory detector that can detect issues such as buffer overflows and use-after-free. Compile with the flags -fsanitize=address and -g.

(1) Capturing Stack Buffer Overflow Issues:

AddressSanitizer.c:

// WeChat Official Account: Embedded Mixed Cuisine
#include <stdlib.h>

void test_func(void)
{
    int a[6] = {0};
    int b = a[6];    // Stack buffer overflow
}                     

int main(int argc, char **argv)
{
 test_func();

 return 0;
}

Compile and Run:

gcc AddressSanitizer.c -fsanitize=address -g -o AddressSanitizer
Essential Tools for Embedded Development: Sanitizer

Execution Result Analysis:

The detection error level was triggered, terminating the program and providing the reason for the abnormal program run and the location of the error in the code.

(2) Capturing Use-After-Free Issues:

ThreadSanitizer.c:

// WeChat Official Account: Embedded Mixed Cuisine
#include <stdlib.h>

void test_func(void)
{
    char *p = malloc(10);
    p[0] = 1;
    free(p);
    p[0] = 1;  // Use after free
}                     

int main(int argc, char **argv)
{
 test_func();

 return 0;
}
Essential Tools for Embedded Development: Sanitizer

2. Example of Using ThreadSanitizer

ThreadSanitizer (TSan) is a data race detector that can be used to analyze thread races, deadlocks, and other thread-related issues. Compile with the flags -fsanitize=thread and -g.

Capturing inter-thread data race issues:

// WeChat Official Account: Embedded Mixed Cuisine
#include <stdio.h>
#include <pthread.h>

int g_counter = 0;  // Data shared by thread1 and thread2

void *increment(void *arg)
{
    g_counter++;
}

void *decrement(void *arg)
{
    g_counter--;
}

void test_func(void)
{
    pthread_t thread1, thread2;

    pthread_create(&thread1, NULL, increment, NULL);
    pthread_create(&thread2, NULL, decrement, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("Counter value: %d\n", g_counter);
}

int main(int argc, char **argv)
{
    test_func();

    return 0;
}

Compile and Run:

gcc ThreadSanitizer.c -fsanitize=thread -g -pthread -o ThreadSanitizer
Essential Tools for Embedded Development: Sanitizer

Execution Result Analysis:

The detection warning level was triggered, the program continued to run, and provided the reasons for the risks in the program and the locations of the risky code.

3. What If Multiple Risks Exist in the Program?

The above examples used the AddressSanitizer and ThreadSanitizer to detect corresponding anomalies, allowing for relatively precise detection of the anomalies.

But what if multiple risks exist in the program?

This is quite close to our practical applications, as we do not know what risks may exist in our code. How can we detect in this case?

Can we compile with multiple -fsanitize flags to invoke multiple detectors?

It is possible to include multiple flags, but some detectors cannot be used simultaneously.

Essential Tools for Embedded Development: Sanitizer
Essential Tools for Embedded Development: Sanitizer

AddressSanitizer and ThreadSanitizer cannot be used simultaneously.

However, if our program happens to have both address and thread exceptions, what would be the performance of using the AddressSanitizer and ThreadSanitizer detectors alone?

For example, we can put the three example codes together:

test.c:

// WeChat Official Account: Embedded Mixed Cuisine
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int g_counter = 0;  // Data shared by thread1 and thread2

void *increment(void *arg)
{
    g_counter++;
}

void *decrement(void *arg)
{
    g_counter--;
}

// Test: Resource competition
void test_func(void)
{
    pthread_t thread1, thread2;

    pthread_create(&thread1, NULL, increment, NULL);
    pthread_create(&thread2, NULL, decrement, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("Counter value: %d\n", g_counter);
}

// Test: Use-after-free
void test_func1(void)
{
    char *p = malloc(10);

    printf("This is test_func1\n");

    p[0] = 1;
    free(p);
    p[0] = 1;  // Use after free
}     

// Test: Stack buffer overflow
void test_func2(void)
{
    int a[6] = {0};
    int b = a[6];    // Stack buffer overflow
}     

int main(int argc, char **argv)
{
    test_func();
    test_func1();
test_func2();

    return 0;
}

Compile and run with -fsanitize=thread:

Essential Tools for Embedded Development: Sanitizer

Execution Result Analysis:

The ThreadSanitizer was able to detect the resource competition issue, as well as the use-after-free issue in test_func1 and reported it at the warning level, but it did not detect the stack buffer overflow issue in test_func2.

Is it because test_func2 ran after test_func1, so the anomaly in test_func2 was not detected by the ThreadSanitizer?

Let’s swap the positions and see:

int main(int argc, char **argv)
{
    test_func();
test_func2();
    test_func1();

    return 0;
}
Essential Tools for Embedded Development: Sanitizer

Clearly, the execution result remains the same, and the stack buffer overflow issue in test_func2 was still not detected by the ThreadSanitizer.

Therefore, we can roughly conclude that when both thread and address anomalies exist in the program, using the ThreadSanitizer can accurately detect thread anomalies and detect some address anomalies.

Compile and run with -fsanitize=address:

Execution order:

int main(int argc, char **argv)
{
    test_func();
    test_func1();
    test_func2();

    return 0;
}
Essential Tools for Embedded Development: Sanitizer

Execution Result Analysis:

The AddressSanitizer detected the use-after-free anomaly in test_func1 and reported it at the error level, terminating the program; it did not detect the resource competition risk in test_func; nor did it detect the stack buffer overflow issue in test_func2, because by the time it reached test_func1, the program had already been terminated. If test_func2 was placed before test_func1, it would have detected the anomaly in test_func2.

Conclusion: When both thread and address anomalies exist in the program, using the AddressSanitizer can accurately detect the first triggered address anomaly, but cannot detect the thread anomaly.

When multiple potential risks exist in the program, it is necessary to use multiple detectors to check each one individually. Each detector has its strengths in detection, and after preliminary analysis, one can determine the general direction and select the appropriate detector for the analysis.

That concludes our brief introduction and usage sharing on Sanitizer. For more information about Sanitizer, please refer to: https://github.com/google/sanitizers/wiki/

Essential Tools for Embedded Development: Sanitizer

Writing is not easy, if this article has helped you, please like and follow, thank you everyone!

Exciting Content:
Some rules for log debugging in embedded systems!
A summary of some practical tools in embedded systems!
Easy to understand | A step-by-step guide to writing your first upper computer!
Let’s take a look at some popular Git visualization tools!
Light as a feather, ultra-light embedded database!
Recommended: A useful static code scanning tool for embedded systems!
Protocol compatibility issues involved in upgrades in embedded systems?
Testable software design in embedded systems!
Several highly regarded C language projects, how many do you know?

Leave a Comment