diff --git a/docs/Compiler-Hardening-Guides/Compiler-Annotations-for-C-and-C++.md b/docs/Compiler-Hardening-Guides/Compiler-Annotations-for-C-and-C++.md
index 55f126b9..025edcca 100644
--- a/docs/Compiler-Hardening-Guides/Compiler-Annotations-for-C-and-C++.md
+++ b/docs/Compiler-Hardening-Guides/Compiler-Annotations-for-C-and-C++.md
@@ -2,27 +2,27 @@
> ⓘ NOTE: _This is a draft document by the [Open Source Security Foundation (OpenSSF)](https://openssf.org) [Best Practices Working Group](https://best.openssf.org/). Help to [improve it on GitHub](https://github.com/ossf/wg-best-practices-os-developers/edit/main/docs/Compiler-Hardening-Guides/Compiler-Annotations-for-C-and-C++.md)._
-Compile time security analysis and runtime mitigation implemented in compilers both depend on the compiler being able to see the flow of data between different points in a program, across functions and modules. This is quite a challenge in C and C++ because both languages allow passing around opaque references, thus losing information about objects. To work around this problem, both GCC and Clang implement attributes to annotate source code, especially functions and data structures, to allow them to do better analysis of source code. These annotations are not only beneficial for security, but they also help the compilers make better optimization decisions, often resulting in better code.
+Compile time security analysis and runtime mitigation implemented in compilers both depend on the compiler being able to see the flow of data between different points in a program, across functions and modules. This is quite a challenge in C and C++ because both languages allow passing around opaque references, thus losing information about objects. To work around this problem, both GCC and Clang implement attributes to annotate functions and data structures, enabling better analysis. These annotations improve security. They also help compilers make better optimization decisions, often resulting in better code.
## Attributes at a glance
-Both GCC and Clang recognize the `__attribute__` keyword to annotate source code. Both compilers also provide a `__has_attribute()` macro function that returns 1 if the attribute name passed to it is supported and 0 otherwise. For example `__has_attribute(malloc)` would return 1 in the latest GCC and Clang. The full syntax description for the `__attribute__` keyword is available in the GCC documentation[^GCCATTR].
+Both GCC and Clang recognize the `__attribute__` keyword to annotate source code. Both compilers also provide a `__has_attribute()` macro that returns 1 if the attribute name passed to it is supported and 0 otherwise. For example `__has_attribute(malloc)` would return 1 in the latest GCC and Clang. The full syntax description for the `__attribute__` keyword is available in the GCC documentation[^GCCATTR].
-The C++11[^CPP11] and C23[^C23] standards specify a new attribute specifier sequence to standardize the `__attribute__` functionality. The syntax is simply `[[prefix::attribute]]`, where the `prefix` specifies the namespace (e.g. `gnu` for a number of attributes described in this document) and `attribute` is the name of the attribute. This style is recommended whenever it is possible to build your applications to target these standards.
+The C++11[^CPP11] and C23[^C23] standards specify a new attribute specifier sequence to standardize the `__attribute__` functionality. The syntax is simply `[[prefix::attribute]]`, where the `prefix` specifies the namespace (e.g. `gnu` for a number of attributes described in this document) and `attribute` is the name of the attribute. Use this style when you can target these standards.
-When declaring functions, attributes may be added to the function at the end of the declaration, like so:
+When declaring functions, put attributes at the end of the declaration:
~~~c
extern void *custom_allocator (size_t sz) [[gnu::malloc]] [[alloc_size (1)]];
~~~
-At function definition, function attributes come right before the function name:
+In a function definition, place attributes before the function name:
~~~c
void * [[gnu::malloc]] [[gnu::alloc_size (1)]] custom_allocator (size_t sz);
~~~
-Some function attributes can accept parameters that have specific meanings. Parameters can be numbers that indicate the position of the argument to the function; 1 indicates the first argument, 2 the second and so on. Parameters can also be keywords or names of identifiers that have been declared earlier in the program.
+Some function attributes accept parameters. Parameters can be numbers that indicate the position of the argument to the function; 1 indicates the first argument, 2 the second and so on. Parameters can also be keywords or names of identifiers that have been declared earlier in the program.
Table 1: Recommended attributes
@@ -34,7 +34,7 @@ Table 1: Recommended attributes
| `ownership_takes(`_`allocation-type`_`,` _`ptr-index`_`)` | Clang 20.1.0 | Function | Mark function as valid deallocator for _`allocation-type`_. |
| `ownership_holds(`_`allocation-type`_`,` _`ptr-index`_`)` | Clang 20.1.0 | Function | Mark function taking responsibility of deallocation for _`allocation-type`_. |
| `alloc_size(`_`size-index`_`)`
`alloc_size(`_`size-index-1`_`,`_`size-index-2`_`)` | GCC 2.95.3
Clang 4.0.0 | Function | Mark positional arguments holding the allocation size that the returned pointer points to. |
-| `access(`_`mode`_`,`_`ref-pos`_`)`
`access(`_`mode`_`,` _`ref-pos`_`,` _`size-pos`_`)` | GCC 10.0.0 | Function | Mark access restrictions for positional argument. |
+| `access(`_`mode`_`,`_`ref-index`_`)`
`access(`_`mode`_`,` _`ref-index`_`,` _`size-pos`_`)` | GCC 10.0.0 | Function | Mark access restrictions for positional argument. |
| `fd_arg(`_`fd-index`_`)` | GCC 13.1.0 | Function | Mark open file descriptors in positional arguments. |
| `fd_arg_read(`_`fd-index`_`)` | GCC 13.1.0 | Function | Mark readable file descriptors in positional arguments. |
| `fd_arg_write(`_`fd-index`_`)` | GCC 13.1.0 | Function | Mark writable file descriptors in positional arguments. |
@@ -43,7 +43,7 @@ Table 1: Recommended attributes
## Performance considerations
-Attributes influence not only diagnostics generated by the compiler but also the resultant code. As a result, annotating code with attributes will have an impact on performance, although the impact may go either way. The annotation may allow compilers to add more traps for additional security and be conservative about some optimizations, thus impacting performance of output code. At the same time however, it may allow compilers to make some favorable optimization decisions, resulting in generation of smaller and faster running code and often, better code layout.
+Attributes influence not only diagnostics generated by the compiler but also the generated code. As a result, annotations affect performance. They may enable more traps for additional security more conservative optimizations. However, they can also unlock optimizations that make generated code smaller and faster, and often improve code layout.
[^GCCATTR]: GCC team, [Attribute Syntax](https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html), GCC manual, 2024-01-17
[^CPP11]: ISO/IEC, [Programming languages — C++ ("C++11")](https://web.archive.org/web/20240112105643/https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf), ISO/IEC 14882, 2011. Note: The official ISO/IEC specification is paywalled and therefore not publicly available. The final specification draft is publicly available.
@@ -57,16 +57,16 @@ Attributes influence not only diagnostics generated by the compiler but also the
|:--------------------------------------------------------------------------------------------|:---------------------------:|:----------------------------:|:------------------------------------------------------------------------------------------------- |
| `malloc` | GCC 2.95.3
Clang 13.0.0 | Function | Mark custom allocation functions that return non-aliased (possibly NULL) pointers. |
| `malloc (`_`deallocator`_`)` | GCC 11.0.0
Clang 21.0.0 | Function | Associates _`deallocator`_ as the valid deallocator for the storage allocated by marked function. |
-| `malloc (`_`deallocator`_`,` _`ptr-index`_`)` | GCC 11.0.0 | Function | Same as above but also denotes the positional argument here the pointer must be passed. |
+| `malloc (`_`deallocator`_`,` _`ptr-index`_`)` | GCC 11.0.0 | Function | Same as above but also denotes the positional argument where the pointer must be passed. |
| `ownership_returns(`_`allocation-type`_`)` | Clang 20.1.0 | Function | Associate pointers returned by custom allocation function with _`allocation-type`_ . |
| `ownership_takes(`_`allocation-type`_`,` _`ptr-index`_`)` | Clang 20.1.0 | Function | Mark function as valid deallocator for _`allocation-type`_. |
| `ownership_holds(`_`allocation-type`_`,` _`ptr-index`_`)` | Clang 20.1.0 | Function | Mark function taking responsibility of deallocation for _`allocation-type`_. |
-The `malloc` attribute in GCC[^gcc-malloc] and Clang[^clang-malloc] indicates that the function acts like a memory allocation function, meaning it returns a pointer to allocated storage that is disjoint (non-aliased) from the storage for any other object accessible to the caller.
+The `malloc` attribute in GCC[^gcc-malloc] and Clang[^clang-malloc] indicates that the function behaves like an allocator, meaning it returns a pointer to allocated storage that is disjoint (non-aliased) from the storage for any other object accessible to the caller.
-Using the attribute with no arguments is designed to allow the compiler to rely on that the returned pointer does not alias any other valid pointers at the time of return and does not contain pointers to existing objects for program optimization. Functions like `malloc` and `calloc` have this property because they return a pointer to uninitialized or zeroed-out, newly obtained storage. However, functions like `realloc` do not have this property, as they may return pointers to storage containing pointers to existing objects. Additionally, GCC uses the `malloc` attribute to infer that the marked function returns null only infrequently, allowing callers to be optimized based on that assumption.
+The attribute tells the compiler the returned pointer is unique and does not contain pointers to existing objects, enabling optimizations. Functions like `malloc` and `calloc` have this property because they return a pointer to uninitialized or zeroed-out, newly obtained storage. However, functions like `realloc` do not have this property, as they may return pointers to storage containing pointers to existing objects. GCC also assumes such functions rarely return null, enabling caller optimizations.
-In GCC, the `malloc (`_`deallocator`_`)` and `malloc (`_`deallocator`_`,` _`ptr-index`_`)` forms associate the pointer returned by the marked function with the specified _`deallocator`_ function. Here, _`deallocator`_ is a function name that must have been declared before it can be referenced in the attribute and _`ptr-index`_ denotes the positional argument to _`deallocator`_ where the pointer must be passed in order to deallocate the storage. Using these forms of the `malloc` attribute interacts with the GCC `-Wmismatched-dealloc` and `-Wmismatched-new-delete` warnings[^gcc-mismatched-dealloc] and GCC’s static analyzer (`-fanalyzer`[^gcc-analyzer]) to allow it to catch:
+In GCC, the `malloc (`_`deallocator`_`)` and `malloc (`_`deallocator`_`,` _`ptr-index`_`)` forms associate the pointer returned by the marked function with the specified _`deallocator`_ function. Here, _`deallocator`_ must be declared before use. The _`ptr-index`_ denotes the positional argument to _`deallocator`_ where the pointer must be passed to deallocate the storage. Using these forms of the `malloc` attribute interacts with the GCC `-Wmismatched-dealloc` and `-Wmismatched-new-delete` warnings[^gcc-mismatched-dealloc] and GCC’s static analyzer (`-fanalyzer`[^gcc-analyzer]) to allow it to catch:
- **Mismatched deallocation** (`-Wanalyzer-mismatching-deallocation`) if there is an execution path in which the result of an allocation call is passed to a different _`deallocator`_.
- **Double free** (`-Wanalyzer-double-free`) if there is an execution path in which a value is passed more than once to a deallocation call.
@@ -79,14 +79,14 @@ Clang supports both forms of the `malloc` attribute but does not yet implement t
In Clang, the `ownership_returns(`_`allocation-type`_`)` associates the pointer returned by the marked function with an _`allocation-type`_. Here, _`allocation-type`_ is any string which will subsequently be used to detect mismatched allocations in cases where the pointer is passed to a deallocator marked with another _`allocation-type`_. The _`allocation-type`_ `malloc` has a special meaning and causes the Clang static analyzer to treat the associated pointer as though the allocated storage would have been allocated using the standard `malloc()` function, and can subsequently be safely deallocated with the standard `free()` function.
-The Clang `ownership_takes(`_`allocation-type`_`,` _`ptr-index`_`)` attribute marks a function as a deallocator for pointers of _`allocation-type`_ and `ownership_holds(`_`allocation-type`_`,` _`ptr-index`_`)` marks a function as taking over the ownership of a pointer of _`allocation-type`_ and will deallocate it at some unspecified point in the future. Here, _`ptr-index`_ denotes the positional argument to where the pointer must be passed in order to deallocate or take ownerwship of the storage.
+The Clang `ownership_takes(`_`allocation-type`_`,` _`ptr-index`_`)` attribute marks a function as a deallocator for pointers of _`allocation-type`_ and `ownership_holds(`_`allocation-type`_`,` _`ptr-index`_`)` marks a function as taking over the ownership of a pointer of _`allocation-type`_ and will deallocate it at some unspecified point in the future. Here, _`ptr-index`_ denotes the positional argument to where the pointer must be passed in order to deallocate or take ownership of the storage.
-Using the the `ownership_returns`, `ownership_takes`, and `ownership_holds` attributes allows the Clang static analyzer to catch:
+Using the `ownership_returns`, `ownership_takes`, and `ownership_holds` attributes allows the Clang static analyzer to catch:
- **Mismatched deallocation** (`unix.MismatchedDeallocator`) if there is an execution path in which the result of an allocation call of type _`allocation-type`_ is passed to a function annotated with `ownership_takes` or `ownership_holds` with a different allocation type.
- **Double free** (`unix.Malloc`, `cplusplis.NewDelete`) if there is an execution path in which a value is passed more than once to a function annotated with `ownership_takes` or `ownership_holds`.
-- **Use-after-free** (`unix.Malloc`, `cplusplis.NewDelete`) if there is an execution path in which the memory passed by pointer to a function annotated with `ownership_takes` is used after the call. Using memory passed to a function annotated with `ownership_holds` is considered valid.
-- **Memory leaks** (`unix.Malloc`, `cplusplus.NewDeleteLeaks`) if if there is an execution path in which the result of an allocation call goes out of scope without being passed to a function annotated with `ownership_takes` or `ownership_holds`.
+- **Use-after-free** (`unix.Malloc`, `cplusplus.NewDelete`) if there is an execution path in which the memory passed by pointer to a function annotated with `ownership_takes` is used after the call. Using memory passed to a function annotated with `ownership_holds` is considered valid.
+- **Memory leaks** (`unix.Malloc`, `cplusplus.NewDeleteLeaks`) if there is an execution path in which the result of an allocation call goes out of scope without being passed to a function annotated with `ownership_takes` or `ownership_holds`.
- **Dubious `malloc()` arguments involving `sizeof`** (`unix.MallocSizeof`) if the size of the pointer type the returned pointer does not match the size indicated by `sizeof` expression passed as argument to the allocation function.
- **Potentially attacker controlled `size` parameters to allocation functions** (`optin.taint.TaintedAlloc`) if the `size` parameter originates from a tainted source and the analyzer cannot prove that the size parameter is within reasonable bounds (`<= SIZE_MAX/4`).
@@ -131,11 +131,11 @@ void my_hold(void *ptr) __attribute((ownership_holds(my_allocation, 1)));
|:--------------------------------------------------------------------------------------------|:---------------------------:|:----------------------------:|:------------------------------------------------------------------------------------------------- |
| `alloc_size(`_`size-index`_`)`
`alloc_size(`_`size-index-1`_`,`_`size-index-2`_`)` | GCC 2.95.3
Clang 4.0.0 | Function | Mark positional arguments holding the allocation size that the returned pointer points to. |
-The `alloc_size` attribute in GCC[^gcc-alloc_size] and Clang[^clang-alloc_size] indicates that the functional return value points to a memory allocation and the specified positional arguments hold the size of that allocation. The compiler uses this information to improve the correctness of information obtained through the `__builtin_object_size` and `__builtin_dynamic_object_size`[^gcc-object-size]. builtins. This can improve the accuracy of source fortification for unsafe libc usage and buffer overflows as these builtins are used by [`__FORTIFY_SOURCE`](Compiler-Options-Hardening-Guide-for-C-and-C++.html#-D_FORTIFY_SOURCE=3) to determine correct object bounds.
+The `alloc_size` attribute in GCC[^gcc-alloc_size] and Clang[^clang-alloc_size] indicates that the function's return value points to a memory The `alloc_size` attribute in GCC[^gcc-alloc_size] and Clang[^clang-alloc_size] indicates that the function's return value points to a memory allocation and the specified positional arguments hold the size of that allocation. The compiler uses this information to improve the results of `__builtin_object_size` and `__builtin_dynamic_object_size`[^gcc-object-size]. This can improve the accuracy of source fortification for unsafe libc usage and buffer overflows, as these builtins are used by [`__FORTIFY_SOURCE`](Compiler-Options-Hardening-Guide-for-C-and-C++.html#-D_FORTIFY_SOURCE=3) to determine correct object bounds.
-The `alloc_size(`_`size-index`_`)` form acts as a hint to the compiler that the size of the allocation is denoted by the positional argument at _`size-index`_(using one-based indexing). This form can be used for functions with a `malloc`-like API.
+The `alloc_size(`_`size-index`_`)` form tells the compiler that the size of the allocation is denoted by the positional argument at _`size-index`_(using one-based indexing). This form can be used for functions with a `malloc`-like API.
-The `alloc_size(`_`size-index-1`_`,`_`size-index-2`_`)` form acts as a hint to the compiler that the size of the allocation is denoted by the product of the positional arguments at _`size-index-1`_ and _`size-index-2`_. This form can be used for functions with a `calloc`-like API.
+The `alloc_size(`_`size-index-1`_`,`_`size-index-2`_`)` form tells the compiler that the size of the allocation is denoted by the product of the positional arguments at _`size-index-1`_ and _`size-index-2`_. This form can be used for functions with a `calloc`-like API.
In Clang, the size information hints provided via `alloc_size` attribute only affects `__builtin_object_size` and `__builtin_dynamic_object_size` calls for pointer variables that are declared `const`. In GCC the provided size information hints also affect `__builtin_object_size` and `__builtin_dynamic_object_size` calls for non-`const` pointer variables.
@@ -180,7 +180,7 @@ assert(__builtin_object_size(s, 0) == 100);
|:-----------------------------------------------------------------------------------------------|:---------------------------:|:----------------------------:|:------------------------------------------------------------------------------------------------- |
| `access(`_`mode`_`,`_`ref-index`_`)`
`access(`_`mode`_`,`_`ref-index`_`,`_`size-index`_`)` | GCC 11.0.0 | Function | Mark access restrictions for positional argument. |
-The `access` attribute in GCC[^gcc-access] indicates the intended mode in which the annotated function operates on the specified positional argument. GCC uses this information to detect non-confirming accesses by the annotated function or their callers, as well as write-only accesses to objects that are never read from. Diagnostics of such non-conforming accesses are reported through the `-Wstringop-overread`, `-Wstringop-overflow`, `-Wuninitialized`, `-Wmaybe-uninitialized`, and `-Wunused` warnings.
+The `access` attribute in GCC[^gcc-access] specifies how the function uses the specified argument. GCC uses this to detect nonconforming accesses and write-only accesses to objects that are never read. Diagnostics of such non-conforming accesses are reported through compiler warnings. Examples include `-Wstringop-overread`, `-Wstringop-overflow`, `-Wuninitialized`, `-Wmaybe-uninitialized`, and `-Wunused`.
The `access(`_`mode`_`,`_`ref-index`_`)` form indicates to GCC that the annotated function accesses the object passed to the function by-reference denoted the by the positional argument at _`ref-index`_ (using one-based indexing) according to _`mode`_, where _`mode`_ is one of the following access modes:
@@ -189,34 +189,34 @@ The `access(`_`mode`_`,`_`ref-index`_`)` form indicates to GCC that the annotate
- `read_write`: the pointer or C++ reference corresponding to the specified positional argument may be used to both read and write to the referenced object.
- `none`: the pointer or C++ reference corresponding to the specified positional argument may not be used to access the referenced object at all.
-The `access(`_`mode`_`,`_`ref-index`_`,`_`size-index`_`)` form behaves as the `access(`_`mode`_`,`_`ref-index`_`)` form but additionally hints to the compiler that the maximum size of the object (for the purposes of accesses) referenced by the pointer (or C++ reference) corresponding to the _`ref-index`_ positional argument is is denoted by the positional argument at _`size-index`_. The size is expected to the expressed as number of bytes if the pointer type denoted by _`ref-index`_ is `void*`. Otherwise, the size of expressed as number of elements of the type being referenced by the pointer denoted by _`ref-index`_. The actual bounds of the accesses carried out the function may be less than the size denoted the positional argument at _`size-index`_ but they must not exceed the denoted size.
+The `access(`_`mode`_`,`_`ref-index`_`,`_`size-index`_`)` form behaves as the `access(`_`mode`_`,`_`ref-index`_`)` form but additionally hints to the compiler that the maximum size of the object (for the purposes of accesses) referenced by the pointer (or C++ reference) corresponding to the _`ref-index`_ positional argument is denoted by the positional argument at _`size-index`_. The size is expected to the expressed as the number of bytes if the pointer type denoted by _`ref-index`_ is `void*`. Otherwise, the size is expressed as the number of elements of the type being referenced by the pointer denoted by _`ref-index`_. The actual bounds of the accesses carried out by the function may be less than the size denoted by the positional argument at _`size-index`_ but they must not exceed the denoted size.
The `write_only` and `read_write` access modes are applicable only to non-`const` pointer types. The `read_only` access mode implies a stronger guarantee than the `const` qualifier which may be cast away from a pointer.
-In the `read_only`and `read_write` access modes the object referenced by the pointer corresponding to the _`ref-index`_ must be initialized unless the argument specifying the size of the access denoted by _`size-index`_ is zero. In the `write_only` access mode the object referenced by the pointer need not be initialized.
+In the `read_only` and `read_write` access modes the object referenced by the pointer corresponding to the _`ref-index`_ must be initialized unless the argument specifying the size of the access denoted by _`size-index`_ is zero. In the `write_only` access mode the object referenced by the pointer need not be initialized.
### Example usage
~~~c
-// Denotes that puts will perform read-only access on the memory pointer to by ptr.
+// Denotes that puts performs read-only access on the memory pointed to by ptr.
int puts (const char* ptr) __attribute__ ((access (read_only, 1)));
-// Denotes that strcat will perform read-write access on the memory pointer to by destination and read-only access on the memory pointed to by source.
+// Denotes that strcat performs read-write access on the memory pointed to by destination and read-only access on the memory pointed to by source.
char* strcat (char* destination, const char* source) __attribute__ ((access (read_write, 1), access (read_only, 2)));
-// Denotes that strcpy will perform write-only access on the memory pointer to by destination and read-only access on the memory pointed to by source.
+// Denotes that strcpy performs write-only access on the memory pointed to by destination and read-only access on the memory pointed to by source.
char* strcpy (char* destination, const char* source) __attribute__ ((access (write_only, 1), access (read_only, 2)));
-// Denotes that fgets will perform write-only access up n character on the memory pointed to by destination and read-write access on the memory pointed to by stream.
+// Denotes that fgets performs write-only access up n character on the memory pointed to by buff and read-write access on the memory pointed to by stream.
int fgets (char* buff, int n, FILE* stream) __attribute__ ((access (write_only, 1, 2), access (read_write, 3)));
-// Denotes that print_buffer will perform read-only access up to size characters on memory pointed to by buffer.
+// Denotes that print_buffer performs read-only access up to size characters on memory pointed to by buffer.
void print_buffer(const char *buffer, size_t size) __attribute__((access(read_only, 1, 2)));
-// Denotes that fill_buffer will perform write-only access up to size characters on memory pointed to by buffer.
+// Denotes that fill_buffer performs write-only access up to size characters on memory pointed to by buffer.
void fill_buffer(char *buffer, size_t size) __attribute__((access(write_only, 1, 2)));
-// Denotes that to_uppercase will perform read-write access up to size characters on memory pointed to by buffer.
+// Denotes that to_uppercase performs read-write access up to size characters on memory pointed to by buffer.
void to_uppercase(char *buffer, size_t size) __attribute__((access(read_write, 1, 2)));
~~~
@@ -234,19 +234,19 @@ void to_uppercase(char *buffer, size_t size) __attribute__((access(read_write, 1
| `fd_arg_read(`_`fd-index`_`)` | GCC 13.0.0 | Function | Mark positional argument holding a valid, open, and readable file descriptor. |
| `fd_arg_write(`_`fd-index`_`)` | GCC 13.0.0 | Function | Mark positional argument holding a valid, open, and writable file descriptor. |
-The `fd_arg`, `fd_arg_read`, and `fd_arg_write` attributes in GCC[^gcc-fd_arg] indicate that the annotated function expects an open file descriptor as an argument. GCC’s static analyzer (`-fanalyzer`[^gcc-analyzer]) can use this information to to catch:
+The `fd_arg`, `fd_arg_read`, and `fd_arg_write` attributes in GCC[^gcc-fd_arg] indicate that the annotated function expects an open file descriptor as an argument. GCC’s static analyzer (`-fanalyzer`[^gcc-analyzer]) can use this information to catch:
- **Access mode mismatches** (`-Wanalyzer-fd-access-mode-mismatch`) if there are code paths through which a read on a write-only file descriptor or write on a read-only file descriptor is attempted.
-- **Double-close conditions** (`-Wanalyzer-fd-double-close`) if there are code paths thorough which a file descriptor can be closed more than once.
+- **Double-close conditions** (`-Wanalyzer-fd-double-close`) if there are code paths through which a file descriptor can be closed more than once.
- **File descriptor leaks** (`-Wanalyzer-fd-leak`) if there are code paths through which a file descriptor goes out of scope without being closed.
- **Use-after-close** (`-Wanalyzer-fd-use-after-close`) if there are code paths through which a read or write is attempted on a closed file descriptor.
- **Use-without-check** (`-Wanalyzer-fd-use-without-check`) if there are code paths through which a file descriptor is used without being first checked for validity.
-The `fd_arg(`_`fd-index`_`)` form acts as a hint to the compiler that the positional argument at _`fd-index`_(using one-based indexing) must be an open file descriptor and must have been must have been checked for validity (such as by calling `fcntl(fd, F_GETFD)` on it) before usage.
+The `fd_arg(`_`fd-index`_`)` form acts as a hint to the compiler that the positional argument at _`fd-index`_(using one-based indexing) must be an open file descriptor and must have been checked for validity (such as by calling `fcntl(fd, F_GETFD)` on it) before usage.
-The `fd_arg_read(`_`fd-index`_`)` form is similar to `fd_arg` but also stipulates that the file descriptor must not have been opened as write-only.
+The `fd_arg_read(`_`fd-index`_`)` form is like `fd_arg` but also requires that the file descriptor must not have been opened as write-only.
-The `fd_arg_write(`_`fd-index`_`)` form is similar to `fd_arg` but also stipulates that the file descriptor must not have been opened as read-only.
+The `fd_arg_write(`_`fd-index`_`)` form is like `fd_arg` but also requires that the file descriptor must not have been opened as read-only.
#### Example usage
@@ -273,9 +273,9 @@ void read_from_file (int fd, void *dst, size_t size) __attribute__ ((fd_arg_read
|:-----------------------------------------------------------------------------------------------|:---------------------------:|:----------------------------:|:------------------------------------------------------------------------------------------------- |
| `noreturn` | GCC 2.5.0
Clang 4.0.0 | Function | Mark functions that never return. |
-The `noreturn` attribute indicates that the annotated function never returns control flow to the calling function (e.g. functions that terminate the application such as `abort()` and `exit()`, throw exceptions, loop indefinitely, etc.). Such functions and methods must be declared void.
+The `noreturn` attribute indicates that the annotated function never returns to its caller. Examples include functions that terminate the application (e.g., `abort()` and `exit()`), throw exceptions, or loop indefinitely. Such functions and methods must be declared void.
-Using this attribute allows the compiler to optimize the generated code without regard to what would happen if the annotated function ever did return. In addition, compiler can generate a diagnostic for any function declared as `noreturn` that appears to return to its caller[^clang-noreturn] and `noreturn` functions can improve the accuracy of other diagnostics, e.g., by helping the compiler reduce false warnings for uninitialized variables[^gcc-noreturn].
+This lets the compiler optimize assuming the function never returns. In addition, the compiler can diagnose any function declared as `noreturn` that appears to return[^clang-noreturn]. The attribute can also improve other diagnostics, for example by reducing false warnings for uninitialized variables[^gcc-noreturn].
Users should be careful not to assume that registers saved by the calling function are restored before calling the `noreturn` function.
@@ -293,7 +293,7 @@ fatal (...)
}
~~~
-An alternative way to declare that a function does not return before the `noreturn` attribute was added in GCC 2.5.0 was[^gcc-voidfn]:
+Before GCC 2.5.0, a non-returning function could be declared as[^gcc-voidfn]:
~~~c
typedef void voidfn ();
@@ -308,35 +308,37 @@ volatile voidfn fatal;
---
-### Mark functions functions with arguments that require sanitization
+### Mark functions with arguments that require sanitization
| Attribute | Supported since | Type | Description |
|:------------------------------------------------------------------------------------------ |:---------------------------:|:----------------------------:|:------------------------------------------------------------------------------------------------- |
| `tainted_args` | GCC 12.1.0 | Function or function pointer | Mark functions with arguments that require sanitization. |
-The `tainted_args` attribute indicates that the annotated function requires sanitization of its arguments[^gcc-tainted-args]. GCC's static analyzer (`-fanalyzer`[^gcc-analyzer]) use this information to treat all the function's parameters (and buffers pointed to by pointer parameters) as potentially under attacker control. The analyzer can subsequently warn when tainted arguments are used as:
+The `tainted_args` attribute marks functions whose arguments must be sanitized[^gcc-tainted-args]. GCC's static analyzer (`-fanalyzer`[^gcc-analyzer]) uses this information to treat all parameters (and pointed-to buffers) as potentially attacker-controlled. It then checks how those values are used. The analyzer can subsequently warn when tainted arguments are used as:
- **Allocation sizes** (`-Wanalyzer-tainted-allocation-size`) if there are code paths through which a tainted argument is used as a size argument to an memory allocation function such as `malloc()` without sanitization.
-- **Part of assertation conditions** (`-Wno-analyzer-tainted-assertion`) if there are code paths through which a tainted argument is used in a condition without sanitization which can lead to a function annotated with `noreturn`, such as assertion failure handlers.
+- **Part of assertion conditions** (`-Wno-analyzer-tainted-assertion`) if there are code paths through which a tainted argument is used in a condition without sanitization which can lead to a function annotated with `noreturn`, such as assertion failure handlers.
- **Array index** (`-Wno-analyzer-tainted-array-index`) if there are code paths through which a tainted argument is used as an array index without sanitization, potentially exposing the code to out-of-bounds conditions.
-- **Divisor** (`-Wanalyzer-tainted-divisor`) if there code paths through which a tainted argument is used a divisor in an arithmetic division operations without sanitization, potentially exposing the code to division-by-zero errors.
+- **Divisor** (`-Wanalyzer-tainted-divisor`) if there are code paths through which a tainted argument is used as a divisor in an arithmetic division operations without sanitization, potentially exposing the code to division-by-zero errors.
- **Pointer offsets** (`-Wanalyzer-tainted-offset`) if there are code paths through which a tainted argument is used an offset in pointer arithmetic without sanitization, potentially exposing the code to spatial-safety violations.
- **Sizes** (`-Wanalyzer-tainted-size`) if there are code paths through which a tainted argument is used a size argument to a (non-memory-allocation) function, such as `memset()`, potentially exposing the code to spatial-safety violations.
The main use case of the `tainted_args` attribute is annotating the program's attack surface, i.e., the functions that are exposed to untrusted, potentially malicious inputs originating from outside the program. The associated static analysis ensures that such untrusted input cannot propagate to sensitive operations without sanitization.
-The `tainted_arg` attribute can be used both in function declarations, and field declarations containing function pointers. In the latter case, any function used as an initializer of such a callback field will be treated as being called with tainted arguments.
+You can apply `tainted_args` to function declarations and to fields that hold function pointers. In the latter case, any function used as an initializer of such a callback field will be treated as being called with tainted arguments.
Prior to GCC 14.1.0 the GCC analyzer's _taint mode_ had to be explicitly enabled by supplying the `-fanalyzer-checker=taint` option. In GCC 14.1.0 onwards taint tracking and the above diagnostics are enabled by default with the `-fanalyzer` option [^Malcolm23].
### Example usage
~~~c
-// Denotes that the arguments to do_with_untrusted contain values that must be sanitized before use
+// Marks arguments to do_with_untrusted as requiring sanitization
void do_with_untrusted_input(int untrusted_input) __attribute__ ((tainted_args));
~~~
-[[Extended example Compiler Explorer](https://godbolt.org/z/rWzd68YvW)]
+[[Extended example at Compiler Explorer](https://godbolt.org/z/rWzd68YvW)]
[^gcc-tainted-args]: GCC team, [Using the GNU Compiler Collection (GCC): 6.35.1 Common Function Attributes: tainted_args](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-tainted_005fargs-function-attribute), GCC Manual, 2025-08-08.
[^Malcolm23]: Malcolm, David. [Enable "taint" state machine with -fanalyzer without requiring -fanalyzer-checker=taint](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103533#c9), GCC Bug 103533, 2023-12-01.
+
+## References