Address Sanitizer

Most recent compilers support a tool called address sanitizer (or ASan) for detecting bugs in C and C++ programs for some improper uses of pointers. In this reading, you will read the official documentation and learn to use this tool which should save you time and effort as well as reduce frustration in the assignments to come.

Your background in the course so far is not enough (yet!) to understand all parts of the official documentation. So I'm going to focus on specific parts that you should be able to understand now. I strongly encourage you to remember the parts you do not understand, since by the end of this course you should be able to understand everything.

You should keep the official documentation open while you work through this reading.

Like the documentation, you will use clang for this reading. However, gcc also supports address sanitizer. Moving between the two is not difficult.

In the sections below, I focus on the bugs you're most likely going to encounter in C programs (as opposed to C++ programs).

Compiling your program with address sanitizer

Usually you compile programs like this:

clang program.c -o program

Read the Using AddressSanitizer section to work out how you must modify this command to add address sanitizer checking.

Detecting stack buffer overflows

A stack buffer overflow is a classic memory corruption bug caused by reading or writing past local array variable bounds. They can be exploited to hijack a program's control flow. ASan can detect these errors immediately.

Compile the code below using address sanitizer:

/* sbo.c */
#include <stdio.h>

int main(void) {
    int a[5], b[10];
    int i;

    for(i = 0; i < 5; i++) {
    	  a[i] = i;
    }

    for(i = 0; i <= 10; i++) {
    	  b[i] = i;
    }
}

Now, run the program. It should crash with an error immediately. Use the information in the error message to fix the bug. The error looks like this:

=================================================================
==29335==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff1e2156e8 at pc 0x47b88b bp 0x7fff1e215590 sp 0x7fff1e215588
...

Fix the bug, recompile and rerun the program. It should not crash.

For curiosity's sake, try compiling the original program without address sanitizer. What happens? Try changing the loop bounds to cause a stack overflow.

Later in the course, we'll study stack overflows in details in an assignment.

Detecting global buffer overflows

Global memory buffers are global array variables. Reading or writing past them can cause silent errors, though rarely the programs also crash. Recent versions of ASan allow detecting these errors immediately.

Compile the code below using address sanitizer:

/* gbo.c */
#include <stdio.h>

int a[5], b[10];

int main(void) {
    int i;

    for(i = 0; i <= 5; i++) {
    	  a[i] = i;
    }

    for(i = 0; i < 10; i++) {
    	  b[i] = i;
    }
}

Run it, it should crash too. The error message is less precise this time, but you should be able to figure it out.

Note if the program runs without crashing, you are probably using a clang that is too old. Use the clang on the cycle machines (clang-14).

Detecting Use-after-return

A use-after-return bug refers to using a pointer that contains an address referencing a stack object that has ``died" (because the function has returned). Under normal conditions, these bugs are almost always silent causing corruption. They're also expensive to find. ASan can find these bugs when instructed to do so.

Compile the following code using address sanitizer:

/* uar.c */

#include <stdio.h>

int *value() {
    int x = 5;
    return &x;
}

int main(void) {
    printf("Value is: %d\n", *value());
}

Note when you compile, you should also get a warning about returning the address of a stack variable, almost certainly a wrong thing to do! The warning indicates you should really fix the bug. Nevertheless, continue.

If you run this program as before, it will not crash. Read the example for this detector carefully. Once you set the ASAN_OPTIONS environment variable you should be able to get a crash.

If you don't know how to set environment variables, read the environment documentation for the Bash shell, which is usually the default shell.

Heap Buffer Overflows

A heap buffer overflow occurs when you read or write memory beyond the extent of the dynamic memory allocation. In normal runs, these bugs are usually silent and corrupt memory and data. Using address sanitizer enables these bugs to be detected immediately.

Again, compile and run this program with address sanitizer enabled.

/* hbo.c */
#include <stdlib.h>
#include <stdio.h>

int main(void) {
  int *array;

  array = malloc(100 * sizeof(int));
  array[0] = 0;
  array[100] = 100;

  return array[1];
}

The program should crash immediately. Make sure you can understand the error message. This form of the buffer overflow bug is extremely common.

Heap Use After Free

A heap use-after-free occurs when you free memory but then continue to use it. Usually, under normal conditions, the program will crash with a segmentation fault, but sometimes it will continue to run silently corrupting memory. Use the address sanitizer to cause an immediate crash always so you can identify the bug quickly.

Again, compile and run this program with address sanitizer enabled.

/* uaf.c */

int main(void) {
  int *array;

  array = malloc(100 * sizeof(int));
  array[0] = 0;
  free(array);

  return array[0];
}

The program should crash immediately. Identify and fix the bug. Do not introduce a memory leak when fixing the bug (see the next section).

Memory leaks

A memory leak is a bug where allocated memory is not freed. They are insidious bugs that are most harmful to programs that run for a long time (e.g. browsers and servers) or that process lots of data. Leaks can only be detected accurately once a program ends. Here is a simple example.

Again, compile and run this program with address sanitizer enabled.

/* leak.c */

int main(void) {
  int *array;

  array = malloc(100 * sizeof(int));
  array[0] = 0;

  return array[0];
}

After finishing, address sanitizer should identify that memory leaked. However, little other info is provided. So fixing this in a complex program can be an issue.

Other bugs

Address sanitizer can also find other bugs as described in the documentation. Feel free to read through that documentation and try to understand the bugs.

Feel free to ask questions about the examples given above on Blackboard or during office hours.

The mechanics of using AddressSanitizer will not be on the exams, but the nature and causes of these bugs are certainly fair game.