ⓘ NOTE: This is a draft document by the Open Source Security Foundation (OpenSSF) Best Practices Working Group. Help to improve it on GitHub.
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.
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 documentation1.
The C++112 and C233 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, put attributes at the end of the declaration:
extern void *custom_allocator (size_t sz) [[gnu::malloc]] [[alloc_size (1)]];
In a function definition, place attributes before the function name:
void * [[gnu::malloc]] [[gnu::alloc_size (1)]] custom_allocator (size_t sz);
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
Attribute | Supported since | Type | Description |
---|---|---|---|
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. |
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 . |
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-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. |
noreturn |
GCC 2.5.0 Clang 4.0.0 |
Function | Mark functions that never return. |
tainted_args |
GCC 12.1.0 | Function or function pointer | Mark functions with arguments that require sanitization. |
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.
Attribute | Supported since | Type | Description |
---|---|---|---|
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 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 GCC4 and Clang5 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.
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
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
warnings6 and GCC’s static analyzer (-fanalyzer
7) to allow it to catch:
-Wanalyzer-mismatching-deallocation
) if there is an execution path in which the result of an allocation call is passed to a different deallocator
.-Wanalyzer-double-free
) if there is an execution path in which a value is passed more than once to a deallocation call.-Wanalyzer-possible-null-dereference
) if there are execution paths in which an unchecked result of an allocation call is dereferenced or passed to a function requiring a non-null argument.-Wanalyzer-use-after-free
) if there is an execution path in which the memory passed by pointer to a deallocation call is used after the deallocation.-Wanalyzer-malloc-leak
) if if there is an execution path in which the result of an allocation call goes out of scope without being passed to the deallocation function.-Wanalyzer-free-of-non-heap
) if a deallocation function is used on a global or on-stack variable.Clang supports both forms of the malloc
attribute but does not yet implement the -Wmismatched-dealloc
and -Wmismatched-new-delete
warnings. Instead, Clang provides the ownership_returns
, ownership_takes
, and ownership_holds
attributes8: that interact with the Clang static analyzer9.
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 ownership of the storage.
Using the ownership_returns
, ownership_takes
, and ownership_holds
attributes allows the Clang static analyzer to catch:
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.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
.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.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
.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.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
).GCC malloc
, malloc (
deallocator
)
, and malloc (
deallocator
, ptr-index
)
in C++11 / C23 attribute syntax:
void my_free(void *ptr);
// Denotes that my_malloc will return with a dynamically allocated piece of memory which must be freed using my_free.
void * my_malloc(size_t size) [[gnu::malloc]] [[gnu::malloc(my_free, 1)]];
In __attribute__
keyword syntax:
// Denotes that my_malloc will return with a dynamically allocated piece of memory which must be freed using my_free.
void *my_malloc(size_t size) __attribute__ ((malloc, malloc (my_free, 1))) { … }
Note that to benefit both from the associated optimizations and improved detection of memory errors functions should be marked with both the form of the attribute without arguments and the form of the attribute with one or two arguments. [Extended example at Compiler Explorer]
Clang ownership_returns
, ownership_takes
, and ownership_holds
in C++11 / C23 attribute syntax:
// Denotes that my_malloc will return with a pointer to storage labeled as "my_allocation".
void * my_malloc(size_t size) [[gnu::malloc]] [[clang::ownership_returns(my_allocation)]];
// Denotes that my_free will deallocate storage pointed to by ptr that has been labeled "my_allocation".
voidmy_free(void *ptr) [[clang::ownership_takes(my_allocation, 1)]] ;
// Denotes that my_hold will take over the ownership of storage pointed to by ptr that has been labeled "my_allocation".
void my_hold(void *ptr) [[clang::ownership_holds(my_allocation, 1)]];
In __attribute__
keyword syntax:
// Denotes that my_malloc will return with a pointer to storage of labeled as "my_allocation" .
void *my_malloc(size_t size) __attribute((malloc, ownership_returns(my_allocation)));
// Denotes that my_free will deallocate storage pointed to by ptr that has been labeled "my_allocation".
void my_free(void *ptr) __attribute((ownership_takes(my_allocation, 1)));
// Denotes that my_hold will take over the ownership of storage pointed to by ptr that has been labeled "my_allocation".
void my_hold(void *ptr) __attribute((ownership_holds(my_allocation, 1)));
Attribute | Supported since | Type | Description |
---|---|---|---|
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 GCC10 and Clang11 indicates that the function’s return value points to a memory The alloc_size
attribute in GCC10 and Clang11 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
12. This can improve the accuracy of source fortification for unsafe libc usage and buffer overflows, as these builtins are used by __FORTIFY_SOURCE
to determine correct object bounds.
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 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.
In C++11 / C23 attribute syntax:
// Denotes that my_malloc will return with a pointer to storage capable of holding up to size bytes.
void * my_malloc(size_t size) [[gnu::alloc_size(1)]];
// Denotes that my_realloc will return with a pointer to storage capable of holding up to size bytes.
void * my_realloc(void* ptr, size_t size) [[gnu::alloc_size(2)]];
// Denotes that my_calloc will return with a pointer to storage capable of holding up to n * size bytes.
void * my_calloc(size_t n, size_t size) [[gnu::alloc_size(1, 2)]];
In __attribute__
keyword syntax:
// Denotes that my_malloc will return with a pointer to storage capable of holding up to size bytes.
void *my_malloc(size_t size) __attribute__((alloc_size(1)));
// Denotes that my_realloc will return with a pointer to storage capable of holding up to size bytes.
void *my_realloc(void* ptr, size_t size) __attribute__((alloc_size(2)));
// Denotes that my_calloc will return with a pointer to storage capable of holding up to n * size bytes.
void *my_calloc(size_t n, size_t size) __attribute__((alloc_size(1, 2)));
// The following assertions will evaluate to true in both GCC and Clang
void *const p = my_malloc(100);
assert(__builtin_object_size(p, 0) == 100);
void *const q = my_calloc(20, 5);
assert(__builtin_object_size(q, 0) == 100);
// The following assertions will evaluate to true in GCC
void *r = my_malloc(100);
assert(__builtin_object_size(r, 0) == 100);
void *s = my_calloc(20, 5);
assert(__builtin_object_size(s, 0) == 100);
[Extended example at Compiler Explorer]
Attribute | Supported since | Type | Description |
---|---|---|---|
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 GCC13 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:
read_only
: the pointer or C++ reference corresponding to the specified positional argument may be used to read the referenced object but not write to it.write_only
: the pointer or C++ reference corresponding to the specified positional argument may be used to write the referenced object but not to read from it.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 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 C++11 / C23 attribute syntax:
// Denotes that puts performs read-only access on the memory pointed to by ptr.
int puts (const char* ptr) [[gnu::access(read_only, 1)]];
// 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) [[gnu::access(read_write, 1)]] [[gnu::access(read_only, 2)]];
// 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) [[gnu::access(write_only, 1)]] [[gnu::access(read_only, 2)]];
// Denotes that fgets performs write-only access up to n characters 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) [[gnu::access(write_only, 1, 2)]] [[gnu::access(read_write, 3)];
// 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) [[gnu::access(read_only, 1, 2)]];
// 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) [[gnu::access(write_only, 1, 2)]];
// 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) [[gnu::access(read_write, 1, 2)]];
In __attribute__
keyword syntax:
// 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 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 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 performs write-only access up to 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 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 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 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)));
[Extended example at Compiler Explorer]
Attribute | Supported since | Type | Description |
---|---|---|---|
fd_arg( fd-index ) |
GCC 13.0.0 | Function | Mark positional argument holding a valid and open file descriptor. |
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 GCC14 indicate that the annotated function expects an open file descriptor as an argument. GCC’s static analyzer (-fanalyzer
7) can use this information to catch:
-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.-Wanalyzer-fd-double-close
) if there are code paths through which a file descriptor can be closed more than once.-Wanalyzer-fd-leak
) if there are code paths through which a file descriptor goes out of scope without being closed.-Wanalyzer-fd-use-after-close
) if there are code paths through which a read or write is attempted on a closed file descriptor.-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 checked for validity (such as by calling fcntl(fd, F_GETFD)
on it) before usage.
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 like fd_arg
but also requires that the file descriptor must not have been opened as read-only.
In C++11 / C23 attribute syntax:
// Denotes that use_file expects fd to be a valid and open file descriptor
void use_file (int fd) [[gnu::fd_arg(1)]] ;
// Denotes that write_to_file expects fd to be a valid, open, and writable file descriptor
void write_to_file (int fd, void *src, size_t size) [[gnu::fd_arg_write(1)]];
// Denotes that read_from_file expects fd to be a valid, open, and readable file descriptor
void read_from_file (int fd, void *dst, size_t size) [[gnu::fd_arg_read(1)]];
In __attribute__
keyword syntax:
// Denotes that use_file expects fd to be a valid and open file descriptor
void use_file (int fd) __attribute__ ((fd_arg (1)));
// Denotes that write_to_file expects fd to be a valid, open, and writable file descriptor
void write_to_file (int fd, void *src, size_t size) __attribute__ ((fd_arg_write (1)));
// Denotes that read_from_file expects fd to be a valid, open, and readable file descriptor
void read_from_file (int fd, void *dst, size_t size) __attribute__ ((fd_arg_read (1)));
[Extended example at Compiler Explorer]
Attribute | Supported since | Type | Description |
---|---|---|---|
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 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.
This lets the compiler optimize assuming the function never returns. In addition, the compiler can diagnose any function declared as noreturn
that appears to return15. The attribute can also improve other diagnostics, for example by reducing false warnings for uninitialized variables16.
Users should be careful not to assume that registers saved by the calling function are restored before calling the noreturn
function.
In C++11 / C23 attribute syntax:
// Denotes that fatal will never return
void fatal () [[noreturn]];
In __attribute__
keyword syntax:
// Denotes that fatal will never return
void fatal () __attribute__ ((noreturn));
void /* It does not make sense for a noreturn function to have a return type other than void. */
fatal (...)
{
... /* Print error message. */ ...
exit (1);
}
Before GCC 2.5.0, a non-returning function could be declared as17:
typedef void voidfn ();
volatile voidfn fatal;
[Extended example at Compiler Explorer]
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 marks functions whose arguments must be sanitized18. GCC’s static analyzer (-fanalyzer
7) 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:
-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.-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.-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.-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.-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.-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.
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 19.
In C++11 / C23 attribute syntax:
// Marks arguments to do_with_untrusted as requiring sanitization
void do_with_untrusted_input(int untrusted_input) [[gnu::tainted_args]];
In __attribute__
keyword syntax:
// Marks arguments to do_with_untrusted as requiring sanitization
void do_with_untrusted_input(int untrusted_input) __attribute__ ((tainted_args));
[Extended example at Compiler Explorer]
Copyright 2024, OpenSSF contributors, licensed under CC BY 4.0
GCC team, Attribute Syntax, GCC manual, 2024-01-17 ↩
ISO/IEC, Programming languages — C++ (“C++11”), ISO/IEC 14882, 2011. Note: The official ISO/IEC specification is paywalled and therefore not publicly available. The final specification draft is publicly available. ↩
ISO/IEC, Programming languages — C (“C23”), ISO/IEC 9899:2023, 2023. Note: The official ISO/IEC specification is not available. ↩
GCC team, Using the GNU Compiler Collection (GCC): 6.35.1 Common Function Attributes: malloc, GCC Manual, 2024-08-01. ↩
LLVM team, Attributes in Clang: malloc, Clang Compiler User’s Manual, 2025-03-04. ↩
GCC team, Using the GNU Compiler Collection (GCC): 3.9 Options to Request or Suppress Warnings: -Wmismatched-dealloc, GCC Manual, 2024-08-01. ↩
GCC team, Using the GNU Compiler Collection (GCC): 3.10 Options That Control Static Analysis, GCC Manual, 2024-08-01. ↩ ↩2 ↩3
LLVM team, Attributes in Clang: ownership_holds, ownership_returns, ownership_takes, Clang Compiler User’s Manual, 2025-03-04. ↩
LLVM team, Clang Static Analyzer: 1. Available Checkers¶, Clang Compiler User’s Manual, 2025-03-04. ↩
GCC team, Using the GNU Compiler Collection (GCC): 6.35.1 Common Function Attributes: alloc_size, GCC Manual, 2024-08-01. ↩ ↩2
LLVM team, Attributes in Clang: alloc_size, Clang Compiler User’s Manual, 2025-03-04. ↩ ↩2
GCC team, Using the GNU Compiler Collection (GCC): 6.62 Object Size Checking, GCC Manual, 2024-08-01. ↩
GCC team, Using the GNU Compiler Collection (GCC): 6.35.1 Common Function Attributes: access, GCC Manual, 2024-08-01. ↩
GCC team, Using the GNU Compiler Collection (GCC): 6.35.1 Common Function Attributes: fd_arg, GCC Manual, 2024-08-01. ↩
LLVM team, Attributes in Clang: noreturn, Clang Compiler User’s Manual, 2025-03-04. ↩
GCC team, Using the GNU Compiler Collection (GCC): 6.35.1 Common Function Attributes: noreturn, GCC Manual, 2024-08-01. ↩
GCC team, Using the GNU Compiler Collection (GCC): 6.35.1 Common Function Attributes: noreturn, GCC Manual, 2003-05-25. ↩
GCC team, Using the GNU Compiler Collection (GCC): 6.35.1 Common Function Attributes: tainted_args, GCC Manual, 2025-08-08. ↩
Malcolm, David. Enable “taint” state machine with -fanalyzer without requiring -fanalyzer-checker=taint, GCC Bug 103533, 2023-12-01. ↩