[common] add Clang lifetime safety macros and annotate Heap::String (#13381)

This commit introduces initial support for Clang's Lifetime Safety
Analysis across the OpenThread codebase:

1. Defines abstraction macros in `toolchain.h`:
   - `OT_LIFETIME_BOUND` (`[[clang::lifetimebound]]`)
   - `OT_NOESCAPE` (`[[clang::noescape]]`)
   - `OT_GSL_OWNER` (`[[gsl::Owner]]`)
   - `OT_GSL_POINTER` (`[[gsl::Pointer]]`)
   These macros expand to Clang attributes under C++ LLVM builds
   and gracefully degrade to no-ops or GNU attributes elsewhere.

2. Enables Clang lifetime warning flags in `CMakeLists.txt`:
   - `-Wdangling` and `-Wdangling-gsl`
   - `-Wdangling-assignment` and `-Wdangling-field`
   - `-Wreturn-stack-address`

3. Annotates `Heap::String` (`heap_string.hpp`):
   - Marks class `String` with `OT_GSL_OWNER`.
   - Marks `AsCString()` and `Move()` with `OT_LIFETIME_BOUND` to
     ensure returned C string pointers do not outlive the owner.
This commit is contained in:
Jonathan Hui
2026-07-23 12:58:51 -07:00
committed by GitHub
parent 3be32b5597
commit 83424db741
4 changed files with 56 additions and 5 deletions
+1 -1
View File
@@ -99,7 +99,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
set(OT_CFLAGS
$<$<COMPILE_LANGUAGE:C>:${OT_CFLAGS} -Wall -Wformat-nonliteral -Wextra -Wshadow>
$<$<COMPILE_LANGUAGE:CXX>:${OT_CFLAGS} -Wall -Wformat-nonliteral -Wextra -Wshadow -Wno-c++14-compat -fno-exceptions>
$<$<CXX_COMPILER_ID:Clang>:-Wc99-extensions>
$<$<CXX_COMPILER_ID:Clang>:-Wc99-extensions -Wno-unknown-warning-option -Wdangling -Wdangling-gsl -Wdangling-assignment -Wdangling-field -Wreturn-stack-address>
)
endif()
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (613)
#define OPENTHREAD_API_VERSION (614)
/**
* @addtogroup api-instance
+51
View File
@@ -310,6 +310,57 @@ extern "C" {
#endif
/**
* @def OT_LIFETIME_BOUND
*
* Compiler-specific indication that a function or method return value's lifetime is bound to a parameter or `this`.
*/
/**
* @def OT_NOESCAPE
*
* Compiler-specific indication that a pointer or reference parameter does not escape the function scope.
*/
/**
* @def OT_GSL_OWNER
*
* Compiler-specific indication that a class or struct is a resource owner for lifetime safety analysis.
*/
/**
* @def OT_GSL_POINTER
*
* Compiler-specific indication that a class or struct is a non-owning view or pointer for lifetime safety analysis.
*/
#if defined(__cplusplus) && defined(__clang__) && defined(__has_cpp_attribute)
#if __has_cpp_attribute(clang::lifetimebound)
#define OT_LIFETIME_BOUND [[clang::lifetimebound]]
#endif
#if __has_cpp_attribute(clang::noescape)
#define OT_NOESCAPE [[clang::noescape]]
#endif
#if __has_cpp_attribute(gsl::Owner)
#define OT_GSL_OWNER [[gsl::Owner]]
#endif
#if __has_cpp_attribute(gsl::Pointer)
#define OT_GSL_POINTER [[gsl::Pointer]]
#endif
#endif
#ifndef OT_LIFETIME_BOUND
#define OT_LIFETIME_BOUND
#endif
#ifndef OT_NOESCAPE
#define OT_NOESCAPE
#endif
#ifndef OT_GSL_OWNER
#define OT_GSL_OWNER
#endif
#ifndef OT_GSL_POINTER
#define OT_GSL_POINTER
#endif
/**
* @}
*/
+3 -3
View File
@@ -50,7 +50,7 @@ namespace Heap {
* be reused and/or freed and reallocated when the string is set. The `Heap::String` destructor will always free the
* allocated buffer.
*/
class String : public Unequatable<String>
class OT_GSL_OWNER String : public Unequatable<String>
{
public:
/**
@@ -92,7 +92,7 @@ public:
*
* @returns A pointer to C string buffer or `nullptr` if the `String` is null (never set or freed).
*/
const char *AsCString(void) const { return mStringBuffer; }
const char *AsCString(void) const OT_LIFETIME_BOUND { return mStringBuffer; }
/**
* Sets the string from a given C string.
@@ -132,7 +132,7 @@ public:
*
* @returns An rvalue reference to this `String`.
*/
String &&Move(void) { return static_cast<String &&>(*this); }
String &&Move(void) OT_LIFETIME_BOUND { return static_cast<String &&>(*this); }
/**
* Frees any buffer allocated by the `String`.