From 3070c6c69dddea4c2d39e19677710907bbbb43c0 Mon Sep 17 00:00:00 2001 From: Thomas Nyman Date: Tue, 9 Sep 2025 14:24:12 +0200 Subject: [PATCH 1/3] Add license information to Compiler Annotations for C and C++ Signed-off-by: Thomas Nyman --- .../Compiler-Annotations-for-C-and-C++.md | 4 ++++ 1 file changed, 4 insertions(+) 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 025edcca..eedf6e86 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 @@ -341,4 +341,8 @@ void do_with_untrusted_input(int untrusted_input) __attribute__ ((tainted_args)) [^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. +## License + +Copyright 2024, OpenSSF contributors, licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) + ## References From 467ed115d172a49b72d76184ba1cc1573d1151be Mon Sep 17 00:00:00 2001 From: Thomas Nyman Date: Tue, 9 Sep 2025 14:52:22 +0200 Subject: [PATCH 2/3] Fix typo in attribute access example Signed-off-by: Thomas Nyman --- .../Compiler-Annotations-for-C-and-C++.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 eedf6e86..ecd9ebf4 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 @@ -207,7 +207,7 @@ char* strcat (char* destination, const char* source) __attribute__ ((access (rea // 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 n character on the memory pointed to by buff and read-write access on the memory pointed to by stream. +// 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. From a367a8f618ca6360eb1fed1c5430190e302c9678 Mon Sep 17 00:00:00 2001 From: Thomas Nyman Date: Tue, 9 Sep 2025 14:53:14 +0200 Subject: [PATCH 3/3] Add examples in C++11 and C23 attribute syntax to Compiler Annotations for C and C++ Signed-off-by: Thomas Nyman --- .../Compiler-Annotations-for-C-and-C++.md | 108 +++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) 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 ecd9ebf4..006c7471 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 @@ -92,7 +92,16 @@ Using the `ownership_returns`, `ownership_takes`, and `ownership_holds` attribut #### Example usage -GCC `malloc`, `malloc (`_`deallocator`_`)`, and `malloc (`_`deallocator`_, _`ptr-index`_`)` : +GCC `malloc`, `malloc (`_`deallocator`_`)`, and `malloc (`_`deallocator`_, _`ptr-index`_`)` in C++11 / C23 attribute syntax: + +~~~c +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: ~~~c void my_free(void *ptr); @@ -103,7 +112,20 @@ 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](https://godbolt.org/z/bc97ahbnd)] -Clang `ownership_returns`, `ownership_takes`, and `ownership_holds`: +Clang `ownership_returns`, `ownership_takes`, and `ownership_holds` in C++11 / C23 attribute syntax: + +~~~c +// 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: ~~~c // Denotes that my_malloc will return with a pointer to storage of labeled as "my_allocation" . @@ -141,6 +163,21 @@ In Clang, the size information hints provided via `alloc_size` attribute only af #### Example usage +In C++11 / C23 attribute syntax: + +~~~c +// 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: + ~~~c // 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))); @@ -197,6 +234,33 @@ In the `read_only` and `read_write` access modes the object referenced by the po ### Example usage +In C++11 / C23 attribute syntax: + +~~~c +// 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: + ~~~c // Denotes that puts performs read-only access on the memory pointed to by ptr. int puts (const char* ptr) __attribute__ ((access (read_only, 1))); @@ -250,6 +314,21 @@ The `fd_arg_write(`_`fd-index`_`)` form is like `fd_arg` but also requires that #### Example usage +In C++11 / C23 attribute syntax: + +~~~c +// 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: + ~~~c // Denotes that use_file expects fd to be a valid and open file descriptor void use_file (int fd) __attribute__ ((fd_arg (1))); @@ -281,6 +360,22 @@ Users should be careful not to assume that registers saved by the calling functi #### Example usage +In C++11 / C23 attribute syntax: + +~~~c +// Denotes that fatal will never return +void fatal () [[noreturn]]; + +void +fatal (...) +{ + ... /* Print error message. */ ... + exit (1); +} +~~~ + +In `__attribute__` keyword syntax: + ~~~c // Denotes that fatal will never return void fatal () __attribute__ ((noreturn)); @@ -331,6 +426,15 @@ Prior to GCC 14.1.0 the GCC analyzer's _taint mode_ had to be explicitly enabled ### Example usage +In C++11 / C23 attribute syntax: + +~~~c +// Marks arguments to do_with_untrusted as requiring sanitization +void do_with_untrusted_input(int untrusted_input) [[gnu::tainted_args]]; +~~~ + +In `__attribute__` keyword syntax: + ~~~c // Marks arguments to do_with_untrusted as requiring sanitization void do_with_untrusted_input(int untrusted_input) __attribute__ ((tainted_args));