231 lines · plain
1=================2Allocation Tokens3=================4 5.. contents::6 :local:7 8Introduction9============10 11Clang provides support for allocation tokens to enable allocator-level heap12organization strategies. Clang assigns mode-dependent token IDs to allocation13calls; the runtime behavior depends entirely on the implementation of a14compatible memory allocator.15 16Possible allocator strategies include:17 18* **Security Hardening**: Placing allocations into separate, isolated heap19 partitions. For example, separating pointer-containing types from raw data20 can mitigate exploits that rely on overflowing a primitive buffer to corrupt21 object metadata.22 23* **Memory Layout Optimization**: Grouping related allocations to improve data24 locality and cache utilization.25 26* **Custom Allocation Policies**: Applying different management strategies to27 different partitions.28 29Token Assignment Mode30=====================31 32The default mode to calculate tokens is:33 34* ``typehashpointersplit``: This mode assigns a token ID based on the hash of35 the allocated type's name, where the top half ID-space is reserved for types36 that contain pointers and the bottom half for types that do not contain37 pointers.38 39Other token ID assignment modes are supported, but they may be subject to40change or removal. These may (experimentally) be selected with ``-Xclang41-falloc-token-mode=<mode>``:42 43* ``typehash``: This mode assigns a token ID based on the hash of the allocated44 type's name.45 46* ``random``: This mode assigns a statically-determined random token ID to each47 allocation site.48 49* ``increment``: This mode assigns a simple, incrementally increasing token ID50 to each allocation site.51 52The following command-line options affect generated token IDs:53 54* ``-falloc-token-max=<N>``55 Configures the maximum number of token IDs. By default the number of tokens56 is bounded by ``SIZE_MAX``.57 58Querying Token IDs with ``__builtin_infer_alloc_token``59=======================================================60 61For use cases where the token ID must be known at compile time, Clang provides62a builtin function:63 64.. code-block:: c65 66 size_t __builtin_infer_alloc_token(<args>, ...);67 68This builtin returns the token ID inferred from its argument expressions, which69mirror arguments normally passed to any allocation function. The argument70expressions are **unevaluated**, so it can be used with expressions that would71have side effects without any runtime impact.72 73For example, it can be used as follows:74 75.. code-block:: c76 77 struct MyType { ... };78 void *__partition_alloc(size_t size, size_t partition);79 #define partition_alloc(...) __partition_alloc(__VA_ARGS__, __builtin_infer_alloc_token(__VA_ARGS__))80 81 void foo(void) {82 MyType *x = partition_alloc(sizeof(*x));83 }84 85Allocation Token Instrumentation86================================87 88To enable instrumentation of allocation functions, code can be compiled with89the ``-fsanitize=alloc-token`` flag:90 91.. code-block:: console92 93 % clang++ -fsanitize=alloc-token example.cc94 95The instrumentation transforms allocation calls to include a token ID. For96example:97 98.. code-block:: c99 100 // Original:101 ptr = malloc(size);102 103 // Instrumented:104 ptr = __alloc_token_malloc(size, <token id>);105 106Runtime Interface107-----------------108 109A compatible runtime must be provided that implements the token-enabled110allocation functions. The instrumentation generates calls to functions that111take a final ``size_t token_id`` argument.112 113.. code-block:: c114 115 // C standard library functions116 void *__alloc_token_malloc(size_t size, size_t token_id);117 void *__alloc_token_calloc(size_t count, size_t size, size_t token_id);118 void *__alloc_token_realloc(void *ptr, size_t size, size_t token_id);119 // ...120 121 // C++ operators (mangled names)122 // operator new(size_t, size_t)123 void *__alloc_token__Znwm(size_t size, size_t token_id);124 // operator new[](size_t, size_t)125 void *__alloc_token__Znam(size_t size, size_t token_id);126 // ... other variants like nothrow, etc., are also instrumented.127 128Fast ABI129--------130 131An alternative ABI can be enabled with ``-fsanitize-alloc-token-fast-abi``,132which encodes the token ID in the allocation function name.133 134.. code-block:: c135 136 void *__alloc_token_0_malloc(size_t size);137 void *__alloc_token_1_malloc(size_t size);138 void *__alloc_token_2_malloc(size_t size);139 ...140 void *__alloc_token_0_Znwm(size_t size);141 void *__alloc_token_1_Znwm(size_t size);142 void *__alloc_token_2_Znwm(size_t size);143 ...144 145This ABI provides a more efficient alternative where146``-falloc-token-max`` is small.147 148Instrumenting Non-Standard Allocation Functions149-----------------------------------------------150 151By default, AllocToken only instruments standard library allocation functions.152This simplifies adoption, as a compatible allocator only needs to provide153token-enabled variants for a well-defined set of standard functions.154 155To extend instrumentation to custom allocation functions, enable broader156coverage with ``-fsanitize-alloc-token-extended``. Such functions require being157marked with the `malloc158<https://clang.llvm.org/docs/AttributeReference.html#malloc>`_ or `alloc_size159<https://clang.llvm.org/docs/AttributeReference.html#alloc-size>`_ attributes160(or a combination).161 162For example:163 164.. code-block:: c165 166 void *custom_malloc(size_t size) __attribute__((malloc));167 void *my_malloc(size_t size) __attribute__((alloc_size(1)));168 169 // Original:170 ptr1 = custom_malloc(size);171 ptr2 = my_malloc(size);172 173 // Instrumented:174 ptr1 = __alloc_token_custom_malloc(size, token_id);175 ptr2 = __alloc_token_my_malloc(size, token_id);176 177Disabling Instrumentation178-------------------------179 180To exclude specific functions from instrumentation, you can use the181``no_sanitize("alloc-token")`` attribute:182 183.. code-block:: c184 185 __attribute__((no_sanitize("alloc-token")))186 void* custom_allocator(size_t size) {187 return malloc(size); // Uses original malloc188 }189 190Note: Independent of any given allocator support, the instrumentation aims to191remain performance neutral. As such, ``no_sanitize("alloc-token")``192functions may be inlined into instrumented functions and vice-versa. If193correctness is affected, such functions should explicitly be marked194``noinline``.195 196The ``__attribute__((disable_sanitizer_instrumentation))`` is also supported to197disable this and other sanitizer instrumentations.198 199Suppressions File (Ignorelist)200------------------------------201 202AllocToken respects the ``src`` and ``fun`` entity types in the203:doc:`SanitizerSpecialCaseList`, which can be used to omit specified source204files or functions from instrumentation.205 206.. code-block:: bash207 208 [alloc-token]209 # Exclude specific source files210 src:third_party/allocator.c211 # Exclude function name patterns212 fun:*custom_malloc*213 fun:LowLevel::*214 215.. code-block:: console216 217 % clang++ -fsanitize=alloc-token -fsanitize-ignorelist=my_ignorelist.txt example.cc218 219Conditional Compilation with ``__SANITIZE_ALLOC_TOKEN__``220-----------------------------------------------------------221 222In some cases, one may need to execute different code depending on whether223AllocToken instrumentation is enabled. The ``__SANITIZE_ALLOC_TOKEN__`` macro224can be used for this purpose.225 226.. code-block:: c227 228 #ifdef __SANITIZE_ALLOC_TOKEN__229 // Code specific to -fsanitize=alloc-token builds230 #endif231