# Sanitizer special case list

```{contents}
:local:
```

## Introduction

This document describes the way to disable or alter the behavior of
sanitizer tools for certain source-level entities by providing a special
file at compile-time.

## Goal and usage

Users of sanitizer tools, such as {doc}`AddressSanitizer`,
{doc}`HardwareAssistedAddressSanitizerDesign`, {doc}`ThreadSanitizer`,
{doc}`MemorySanitizer` or {doc}`UndefinedBehaviorSanitizer` may want to disable
or alter some checks for certain source-level entities to:

- speedup hot function, which is known to be correct;
- ignore a function that does some low-level magic (e.g. walks through the
  thread stack, bypassing the frame boundaries);
- ignore a known problem.

To achieve this, user may create a file listing the entities they want to
ignore, and pass it to clang at compile-time using
`-fsanitize-ignorelist` flag. See {doc}`UsersManual` for details.

## Example

```bash
$ cat foo.c
#include <stdlib.h>
void bad_foo() {
  int *a = (int*)malloc(40);
  a[10] = 1;
  free(a);
}
int main() { bad_foo(); }
$ cat ignorelist.txt
# Ignore reports from bad_foo function.
fun:bad_foo
$ clang -fsanitize=address foo.c ; ./a.out
# AddressSanitizer prints an error report.
$ clang -fsanitize=address -fsanitize-ignorelist=ignorelist.txt foo.c ; ./a.out
# No error report here.
```

## Usage with UndefinedBehaviorSanitizer

`unsigned-integer-overflow`, `signed-integer-overflow`,
`implicit-signed-integer-truncation`,
`implicit-unsigned-integer-truncation`, and `enum` sanitizers support the
ability to adjust instrumentation based on type.

By default, supported sanitizers will have their instrumentation disabled for
entries specified within an ignorelist.

```bash
$ cat foo.c
void foo() {
  int a = 2147483647; // INT_MAX
  ++a;                // Normally, an overflow with -fsanitize=signed-integer-overflow
}
$ cat ignorelist.txt
[signed-integer-overflow]
type:int
$ clang -fsanitize=signed-integer-overflow -fsanitize-ignorelist=ignorelist.txt foo.c ; ./a.out
# no signed-integer-overflow error
```

For example, supplying the above `ignorelist.txt` to
`-fsanitize-ignorelist=ignorelist.txt` disables overflow sanitizer
instrumentation for arithmetic operations containing values of type `int`.

The `=sanitize` category is also supported. Any `=sanitize` category
entries enable sanitizer instrumentation, even if it was ignored by entries
before. Entries can be `src`, `type`, `global`, `fun`, and
`mainfile`.

With this, one may disable instrumentation for some or all types and
specifically allow instrumentation for one or many types -- including types
created via `typedef`. This is a way to achieve a sort of "allowlist" for
supported sanitizers.

```bash
$ cat ignorelist.txt
[implicit-signed-integer-truncation]
type:*
type:T=sanitize

$ cat foo.c
typedef char T;
typedef char U;
void foo(int toobig) {
  T a = toobig;    // instrumented
  U b = toobig;    // not instrumented
  char c = toobig; // also not instrumented
}
```

If multiple entries match the source, then the latest entry takes the
precedence. Here are a few examples.

```bash
$ cat ignorelist1.txt
# test.cc will not be instrumented.
src:*
src:*/mylib/*=sanitize
src:*/mylib/test.cc

$ cat ignorelist2.txt
# test.cc will be instrumented.
src:*
src:*/mylib/test.cc
src:*/mylib/*=sanitize

$ cat ignorelist3.txt
# Type T will not be instrumented.
type:*
type:T=sanitize
type:T

$ cat ignorelist4.txt
# Function `bad_bar` will be instrumented.
# Function `good_bar` will not be instrumented.
fun:*
fun:*bar
fun:bad_bar=sanitize
```

### Interaction with Overflow Behavior Types

The `overflow_behavior` attribute provides a more granular, source-level
control that takes precedence over the Sanitizer Special Case List. If a type
is given an `overflow_behavior` attribute, it will override any matching
`type:` entry in a special case list.

This allows developers to enforce a specific overflow behavior for a critical
type, even if a broader rule in the special case list would otherwise disable
instrumentation for it.

```bash
$ cat ignorelist.txt
# Disable signed overflow checks for all types by default.
[signed-integer-overflow]
type:*

$ cat foo.c
// Force 'critical_type' to always have overflow checks,
// overriding the ignorelist.
typedef int __attribute__((overflow_behavior(trap))) critical_type;

void foo(int x) {
  critical_type a = x;
  a++; // Overflow is checked here due to the 'trap' attribute.

  int b = x;
  b++; // Overflow is NOT checked here due to the ignorelist.
}
```

For more details on overflow behavior types, see {doc}`OverflowBehaviorTypes`.

## Format

Ignorelists consist of entries, optionally grouped into sections. Empty lines
and lines starting with "#" are ignored.

:::{note}
Prior to Clang 18, section names and entries described below use a variant of
regex where `*` is translated to `.*`. Clang 18
([D154014](https://reviews.llvm.org/D154014)) switches to glob and plans to remove
regex support in Clang 19.

For Clang 18, regex is supported if `#!special-case-list-v1` is the first
line of the file.

Many special case lists use `.` to indicate the literal character and do
not use regex metacharacters such as `(`, `)`. They are unaffected by the
regex to glob transition. For more details, see [this discourse post](https://discourse.llvm.org/t/use-glob-instead-of-regex-for-specialcaselists/71666).
:::

Section names are globs written in square brackets that denote
which sanitizer the following entries apply to. For example, `[address]`
specifies AddressSanitizer while `[{cfi-vcall,cfi-icall}]` specifies Control
Flow Integrity virtual and indirect call checking. Entries without a section
will be placed under the `[*]` section applying to all enabled sanitizers.

Entries contain an entity type, followed by a colon and a glob,
specifying the names of the entities, optionally followed by an equals sign and
a tool-specific category, e.g. `fun:*ExampleFunc=example_category`.
Two generic entity types are `src` and
`fun`, which allow users to specify source files and functions, respectively.
Some sanitizer tools may introduce custom entity types and categories - refer to
tool-specific docs.

```bash
# Lines starting with # are ignored.
# Turn off checks for the source file
# Entries without sections are placed into [*] and apply to all sanitizers
src:path/to/source/file.c
src:*/source/file.c
# Turn off checks for this main file, including files included by it.
# Useful when the main file instead of an included file should be ignored.
mainfile:file.c
# Turn off checks for a particular functions (use mangled names):
fun:_Z8MyFooBarv
# Glob brace expansions and character ranges are supported
fun:bad_{foo,bar}
src:bad_source[1-9].c
# "*" matches zero or more characters
src:bad/sources/*
fun:*BadFunction*
# Specific sanitizer tools may introduce categories.
src:/special/path/*=special_sources
# Sections can be used to limit ignorelist entries to specific sanitizers
[address]
fun:*BadASanFunc*
# Section names are globs
[{cfi-vcall,cfi-icall}]
fun:*BadCfiCall
```

:::{note}
By default, `src` and `mainfile` are matched against the filename as seen
by LLVM. On Windows, this might involve a mix of forward and backslashes as
file separators, and writing patterns to match both variants can be
inconvenient.

Starting with version 4 (indicated by `#!special-case-list-v4`), path matching
on Windows hosts is slash-agnostic: both forward slashes (`/`) and backslashes
(`\`) match either path separator in both patterns and paths.
:::

:::{note}
By default, path matching (for `src` and `mainfile`) matches the query
path as-is. For example, a query with `./foo.c` will not match a rule
defined as `src:foo.c`.

Starting with version 3 (indicated by `#!special-case-list-v3`), leading
`./` is canonicalized (removed) from paths before matching. This means
a rule like `src:foo.c` will match both `foo.c` and `./foo.c`, while
a rule like `src:./foo.c` will no longer match.

Version 4 (indicated by `#!special-case-list-v4`) is a transition version
that maintains backward compatibility by matching both canonicalized and
non-canonicalized paths, but emits a warning if a match would be lost in
Version 5 (i.e., if it only matches because of the deprecated leading `./`
in the rule).

Version 5 (indicated by `#!special-case-list-v5`) drops backward
compatibility and behaves like Version 3.
:::

`mainfile` is similar to applying `-fno-sanitize=` to a set of files but
does not need plumbing into the build system. This works well for internal
linkage functions but has a caveat for C++ vague linkage functions.

C++ vague linkage functions (e.g. inline functions, template instantiations) are
deduplicated at link time. A function (in an included file) ignored by a
specific `mainfile` pattern may not be the prevailing copy picked by the
linker. Therefore, using `mainfile` requires caution. It may still be useful,
e.g. when patterns are picked in a way to ensure the prevailing one is ignored.
(There is action-at-a-distance risk.)

`mainfile` can be useful enabling a ubsan check for a large code base when
finding the direct stack frame triggering the failure for every failure is
difficult.
