| ================== | |
| Source Annotations | |
| ================== | |
| The Clang frontend supports several source-level annotations in the form of | |
| `GCC-style attributes <https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html>`_ | |
| and pragmas that can help make using the Clang Static Analyzer more useful. | |
| These annotations can both help suppress false positives as well as enhance the | |
| analyzer's ability to find bugs. | |
| This page gives a practical overview of such annotations. For more technical | |
| specifics regarding Clang-specific annotations please see the Clang's list of | |
| `language extensions <https://clang.llvm.org/docs/LanguageExtensions.html>`_. | |
| Details of "standard" GCC attributes (that Clang also supports) can | |
| be found in the `GCC manual <https://gcc.gnu.org/onlinedocs/gcc/>`_, with the | |
| majority of the relevant attributes being in the section on | |
| `function attributes <https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_. | |
| Note that attributes that are labeled **Clang-specific** are not | |
| recognized by GCC. Their use can be conditioned using preprocessor macros | |
| (examples included on this page). | |
| .. contents:: | |
| :local: | |
| General Purpose Annotations | |
| ___________________________ | |
| Null Pointer Checking | |
| ##################### | |
| Attribute 'nonnull' | |
| ------------------- | |
| The analyzer recognizes the GCC attribute 'nonnull', which indicates that a | |
| function expects that a given function parameter is not a null pointer. | |
| Specific details of the syntax of using the 'nonnull' attribute can be found in | |
| `GCC's documentation <https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-nonnull-function-attribute>`_. | |
| Both the Clang compiler and GCC will flag warnings for simple cases where a | |
| null pointer is directly being passed to a function with a 'nonnull' parameter | |
| (e.g., as a constant). The analyzer extends this checking by using its deeper | |
| symbolic analysis to track what pointer values are potentially null and then | |
| flag warnings when they are passed in a function call via a 'nonnull' | |
| parameter. | |
| **Example** | |
| .. code-block:: c | |
| int bar(int*p, int q, int *r) __attribute__((nonnull(1,3))); | |
| int foo(int *p, int *q) { | |
| return !p ? bar(q, 2, p) | |
| : bar(p, 2, q); | |
| } | |
| Running ``scan-build`` over this source produces the following output: | |
| .. image:: ../images/example_attribute_nonnull.png | |
| .. _custom_assertion_handlers: | |
| Custom Assertion Handlers | |
| ######################### | |
| The analyzer exploits code assertions by pruning off paths where the | |
| assertion condition is false. The idea is capture any program invariants | |
| specified in the assertion that the developer may know but is not immediately | |
| apparent in the code itself. In this way assertions make implicit assumptions | |
| explicit in the code, which not only makes the analyzer more accurate when | |
| finding bugs, but can help others better able to understand your code as well. | |
| It can also help remove certain kinds of analyzer false positives by pruning off | |
| false paths. | |
| In order to exploit assertions, however, the analyzer must understand when it | |
| encounters an "assertion handler". Typically assertions are | |
| implemented with a macro, with the macro performing a check for the assertion | |
| condition and, when the check fails, calling an assertion handler. For | |
| example, consider the following code fragment: | |
| .. code-block:: c | |
| void foo(int *p) { | |
| assert(p != NULL); | |
| } | |
| When this code is preprocessed on Mac OS X it expands to the following: | |
| .. code-block:: c | |
| void foo(int *p) { | |
| (__builtin_expect(!(p != NULL), 0) ? __assert_rtn(__func__, "t.c", 4, "p != NULL") : (void)0); | |
| } | |
| In this example, the assertion handler is ``__assert_rtn``. When called, | |
| most assertion handlers typically print an error and terminate the program. The | |
| analyzer can exploit such semantics by ending the analysis of a path once it | |
| hits a call to an assertion handler. | |
| The trick, however, is that the analyzer needs to know that a called function | |
| is an assertion handler; otherwise the analyzer might assume the function call | |
| returns and it will continue analyzing the path where the assertion condition | |
| failed. This can lead to false positives, as the assertion condition usually | |
| implies a safety condition (e.g., a pointer is not null) prior to performing | |
| some action that depends on that condition (e.g., dereferencing a pointer). | |
| The analyzer knows about several well-known assertion handlers, but can | |
| automatically infer if a function should be treated as an assertion handler if | |
| it is annotated with the 'noreturn' attribute or the (Clang-specific) | |
| 'analyzer_noreturn' attribute. Note that, currently, clang does not support | |
| these attributes on Objective-C methods and C++ methods. | |
| Attribute 'noreturn' | |
| -------------------- | |
| The 'noreturn' attribute is a GCC attribute that can be placed on the | |
| declarations of functions. It means exactly what its name implies: a function | |
| with a 'noreturn' attribute should never return. | |
| Specific details of the syntax of using the 'noreturn' attribute can be found | |
| in `GCC's documentation <https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-noreturn-function-attribute>`__. | |
| Not only does the analyzer exploit this information when pruning false paths, | |
| but the compiler also takes it seriously and will generate different code (and | |
| possibly better optimized) under the assumption that the function does not | |
| return. | |
| **Example** | |
| On Mac OS X, the function prototype for ``__assert_rtn`` (declared in | |
| ``assert.h``) is specifically annotated with the 'noreturn' attribute: | |
| .. code-block:: c | |
| void __assert_rtn(const char *, const char *, int, const char *) __attribute__((__noreturn__)); | |
| Attribute 'analyzer_noreturn' (Clang-specific) | |
| ---------------------------------------------- | |
| The Clang-specific 'analyzer_noreturn' attribute is almost identical to | |
| 'noreturn' except that it is ignored by the compiler for the purposes of code | |
| generation. | |
| This attribute is useful for annotating assertion handlers that actually | |
| *can* return, but for the purpose of using the analyzer we want to | |
| pretend that such functions do not return. | |
| Because this attribute is Clang-specific, its use should be conditioned with | |
| the use of preprocessor macros. | |
| **Example** | |
| .. code-block:: c | |
| #ifndef CLANG_ANALYZER_NORETURN | |
| #if __has_feature(attribute_analyzer_noreturn) | |
| #define CLANG_ANALYZER_NORETURN __attribute__((analyzer_noreturn)) | |
| #else | |
| #define CLANG_ANALYZER_NORETURN | |
| #endif | |
| #endif | |
| void my_assert_rtn(const char *, const char *, int, const char *) CLANG_ANALYZER_NORETURN; | |
| Dynamic Memory Modeling Annotations | |
| ################################### | |
| If a project uses custom functions for dynamic memory management (that e.g. act as wrappers around ``malloc``/``free`` or ``new``/``delete`` in C++) and the analyzer cannot "see" the _definitions_ of these functions, it's possible to annotate their declarations to let the analyzer model their behavior. (Otherwise the analyzer cannot know that the opaque ``my_free()`` is basically equivalent to a standard ``free()`` call.) | |
| .. note:: | |
| **This page only provides a brief list of these annotations.** For a full documentation, see the main `Attributes in Clang <../../AttributeReference.html#ownership-holds-ownership-returns-ownership-takes-clang-static-analyzer>`_ page. | |
| Attribute 'ownership_returns' (Clang-specific) | |
| ---------------------------------------------- | |
| Use this attribute to mark functions that return dynamically allocated memory. | |
| The first argument is the type of the allocation (e.g. ``malloc``, ``new``, or any other identifier). | |
| An optional second argument is the 1-based index of the function parameter that specifies the allocation size in bytes. | |
| The referenced parameter must have an integral type. | |
| This attribute may appear at most once per function declaration. | |
| .. code-block:: c | |
| // Without size argument: | |
| void __attribute((ownership_returns(malloc))) *my_malloc(size_t sz); | |
| // With size argument (describes that the 1st parameter represents the allocation size in bytes): | |
| void __attribute((ownership_returns(malloc, 1))) *my_sized_malloc(size_t sz); | |
| Attribute 'ownership_takes' (Clang-specific) | |
| -------------------------------------------- | |
| Use this attribute to mark functions that deallocate memory. Takes two arguments: the type of the allocation (e.g. ``malloc`` or ``new``) and the index of the parameter that is being deallocated (counting from 1). | |
| .. code-block:: c | |
| void __attribute((ownership_takes(malloc, 1))) my_free(void *); | |
| Attribute 'ownership_holds' (Clang-specific) | |
| -------------------------------------------- | |
| Use this attribute to mark functions that take ownership of memory and will deallocate it at some unspecified point in the future. Takes two arguments: the type of the allocation (e.g. ``malloc`` or ``new``) and the index of the parameter that is being held (counting from 1). | |
| .. code-block:: c | |
| void __attribute((ownership_holds(malloc, 2))) store_in_table(int key, record_t *val); | |
| The annotations ``ownership_takes`` and ``ownership_holds`` both prevent memory leak reports (concerning the specified parameter); the difference between them is that using taken memory is a use-after-free error, while using held memory is assumed to be legitimate. | |
| Mac OS X API Annotations | |
| ________________________ | |
| .. _cocoa_mem: | |
| Cocoa & Core Foundation Memory Management Annotations | |
| ##################################################### | |
| The analyzer supports the proper management of retain counts for | |
| both Cocoa and Core Foundation objects. This checking is largely based on | |
| enforcing Cocoa and Core Foundation naming conventions for Objective-C methods | |
| (Cocoa) and C functions (Core Foundation). Not strictly following these | |
| conventions can cause the analyzer to miss bugs or flag false positives. | |
| One can educate the analyzer (and others who read your code) about methods or | |
| functions that deviate from the Cocoa and Core Foundation conventions using the | |
| attributes described here. However, you should consider using proper naming | |
| conventions or the `objc_method_family <https://clang.llvm.org/docs/LanguageExtensions.html#the-objc-method-family-attribute>`_ | |
| attribute, if applicable. | |
| .. _ns_returns_retained: | |
| Attribute 'ns_returns_retained' (Clang-specific) | |
| ------------------------------------------------ | |
| The GCC-style (Clang-specific) attribute 'ns_returns_retained' allows one to | |
| annotate an Objective-C method or C function as returning a retained Cocoa | |
| object that the caller is responsible for releasing (via sending a | |
| ``release`` message to the object). The Foundation framework defines a | |
| macro ``NS_RETURNS_RETAINED`` that is functionally equivalent to the | |
| one shown below. | |
| **Placing on Objective-C methods**: For Objective-C methods, this | |
| annotation essentially tells the analyzer to treat the method as if its name | |
| begins with "alloc" or "new" or contains the word | |
| "copy". | |
| **Placing on C functions**: For C functions returning Cocoa objects, the | |
| analyzer typically does not make any assumptions about whether or not the object | |
| is returned retained. Explicitly adding the 'ns_returns_retained' attribute to C | |
| functions allows the analyzer to perform extra checking. | |
| **Example** | |
| .. code-block:: objc | |
| #import <Foundation/Foundation.h>; | |
| #ifndef __has_feature // Optional. | |
| #define __has_feature(x) 0 // Compatibility with non-clang compilers. | |
| #endif | |
| #ifndef NS_RETURNS_RETAINED | |
| #if __has_feature(attribute_ns_returns_retained) | |
| #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) | |
| #else | |
| #define NS_RETURNS_RETAINED | |
| #endif | |
| #endif | |
| @interface MyClass : NSObject {} | |
| - (NSString*) returnsRetained NS_RETURNS_RETAINED; | |
| - (NSString*) alsoReturnsRetained; | |
| @end | |
| @implementation MyClass | |
| - (NSString*) returnsRetained { | |
| return [[NSString alloc] initWithCString:"no leak here"]; | |
| } | |
| - (NSString*) alsoReturnsRetained { | |
| return [[NSString alloc] initWithCString:"flag a leak"]; | |
| } | |
| @end | |
| Running ``scan-build`` on this source file produces the following output: | |
| .. image:: ../images/example_ns_returns_retained.png | |
| .. _ns_returns_not_retained: | |
| Attribute 'ns_returns_not_retained' (Clang-specific) | |
| ---------------------------------------------------- | |
| The 'ns_returns_not_retained' attribute is the complement of | |
| '`ns_returns_retained`_'. Where a function or method may appear to obey the | |
| Cocoa conventions and return a retained Cocoa object, this attribute can be | |
| used to indicate that the object reference returned should not be considered as | |
| an "owning" reference being returned to the caller. The Foundation | |
| framework defines a macro ``NS_RETURNS_NOT_RETAINED`` that is functionally | |
| equivalent to the one shown below. | |
| Usage is identical to `ns_returns_retained`_. When using the | |
| attribute, be sure to declare it within the proper macro that checks for | |
| its availability, as it is not available in earlier versions of the analyzer: | |
| .. code-block:objc | |
| #ifndef __has_feature // Optional. | |
| #define __has_feature(x) 0 // Compatibility with non-clang compilers. | |
| #endif | |
| #ifndef NS_RETURNS_NOT_RETAINED | |
| #if __has_feature(attribute_ns_returns_not_retained) | |
| #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) | |
| #else | |
| #define NS_RETURNS_NOT_RETAINED | |
| #endif | |
| #endif | |
| .. _cf_returns_retained: | |
| Attribute 'cf_returns_retained' (Clang-specific) | |
| ------------------------------------------------ | |
| The GCC-style (Clang-specific) attribute 'cf_returns_retained' allows one to | |
| annotate an Objective-C method or C function as returning a retained Core | |
| Foundation object that the caller is responsible for releasing. The | |
| CoreFoundation framework defines a macro ``CF_RETURNS_RETAINED`` that is | |
| functionally equivalent to the one shown below. | |
| **Placing on Objective-C methods**: With respect to Objective-C methods., | |
| this attribute is identical in its behavior and usage to 'ns_returns_retained' | |
| except for the distinction of returning a Core Foundation object instead of a | |
| Cocoa object. | |
| This distinction is important for the following reason: as Core Foundation is a | |
| C API, the analyzer cannot always tell that a pointer return value refers to a | |
| Core Foundation object. In contrast, it is trivial for the analyzer to | |
| recognize if a pointer refers to a Cocoa object (given the Objective-C type | |
| system). | |
| **Placing on C functions**: When placing the attribute | |
| 'cf_returns_retained' on the declarations of C functions, the analyzer | |
| interprets the function as: | |
| 1. Returning a Core Foundation Object | |
| 2. Treating the function as if it its name contained the keywords | |
| "create" or "copy". This means the returned object as a | |
| +1 retain count that must be released by the caller, either by sending a | |
| ``release`` message (via toll-free bridging to an Objective-C object | |
| pointer), or calling ``CFRelease`` or a similar function. | |
| **Example** | |
| .. code-block:objc | |
| #import <Cocoa/Cocoa.h> | |
| #ifndef __has_feature // Optional. | |
| #define __has_feature(x) 0 // Compatibility with non-clang compilers. | |
| #endif | |
| #ifndef CF_RETURNS_RETAINED | |
| #if __has_feature(attribute_cf_returns_retained) | |
| #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) | |
| #else | |
| #define CF_RETURNS_RETAINED | |
| #endif | |
| #endif | |
| @interface MyClass : NSObject {} | |
| - (NSDate*) returnsCFRetained CF_RETURNS_RETAINED; | |
| - (NSDate*) alsoReturnsRetained; | |
| - (NSDate*) returnsNSRetained NS_RETURNS_RETAINED; | |
| @end | |
| CF_RETURNS_RETAINED | |
| CFDateRef returnsRetainedCFDate() { | |
| return CFDateCreate(0, CFAbsoluteTimeGetCurrent()); | |
| } | |
| @implementation MyClass | |
| - (NSDate*) returnsCFRetained { | |
| return (NSDate*) returnsRetainedCFDate(); // No leak. | |
| } | |
| - (NSDate*) alsoReturnsRetained { | |
| return (NSDate*) returnsRetainedCFDate(); // Always report a leak. | |
| } | |
| - (NSDate*) returnsNSRetained { | |
| return (NSDate*) returnsRetainedCFDate(); // Report a leak when using GC. | |
| } | |
| @end | |
| Running ``scan-build`` on this example produces the following output: | |
| .. image:: ../images/example_cf_returns_retained.png | |
| Attribute 'cf_returns_not_retained' (Clang-specific) | |
| ---------------------------------------------------- | |
| The 'cf_returns_not_retained' attribute is the complement of | |
| '`cf_returns_retained`_'. Where a function or method may appear to obey the | |
| Core Foundation or Cocoa conventions and return a retained Core Foundation | |
| object, this attribute can be used to indicate that the object reference | |
| returned should not be considered as an "owning" reference being | |
| returned to the caller. The CoreFoundation framework defines a macro | |
| **``CF_RETURNS_NOT_RETAINED``** that is functionally equivalent to the one | |
| shown below. | |
| Usage is identical to cf_returns_retained_. When using the attribute, be sure | |
| to declare it within the proper macro that checks for its availability, as it | |
| is not available in earlier versions of the analyzer: | |
| .. code-block:objc | |
| #ifndef __has_feature // Optional. | |
| #define __has_feature(x) 0 // Compatibility with non-clang compilers. | |
| #endif | |
| #ifndef CF_RETURNS_NOT_RETAINED | |
| #if __has_feature(attribute_cf_returns_not_retained) | |
| #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) | |
| #else | |
| #define CF_RETURNS_NOT_RETAINED | |
| #endif | |
| #endif | |
| .. _ns_consumed: | |
| Attribute 'ns_consumed' (Clang-specific) | |
| ---------------------------------------- | |
| The 'ns_consumed' attribute can be placed on a specific parameter in either | |
| the declaration of a function or an Objective-C method. It indicates to the | |
| static analyzer that a ``release`` message is implicitly sent to the | |
| parameter upon completion of the call to the given function or method. The | |
| Foundation framework defines a macro ``NS_RELEASES_ARGUMENT`` that | |
| is functionally equivalent to the ``NS_CONSUMED`` macro shown below. | |
| **Example** | |
| .. code-block:objc | |
| #ifndef __has_feature // Optional. | |
| #define __has_feature(x) 0 // Compatibility with non-clang compilers. | |
| #endif | |
| #ifndef NS_CONSUMED | |
| #if __has_feature(attribute_ns_consumed) | |
| #define NS_CONSUMED __attribute__((ns_consumed)) | |
| #else | |
| #define NS_CONSUMED | |
| #endif | |
| #endif | |
| void consume_ns(id NS_CONSUMED x); | |
| void test() { | |
| id x = [[NSObject alloc] init]; | |
| consume_ns(x); // No leak! | |
| } | |
| @interface Foo : NSObject | |
| + (void) releaseArg:(id) NS_CONSUMED x; | |
| + (void) releaseSecondArg:(id)x second:(id) NS_CONSUMED y; | |
| @end | |
| void test_method() { | |
| id x = [[NSObject alloc] init]; | |
| [Foo releaseArg:x]; // No leak! | |
| } | |
| void test_method2() { | |
| id a = [[NSObject alloc] init]; | |
| id b = [[NSObject alloc] init]; | |
| [Foo releaseSecondArg:a second:b]; // 'a' is leaked, but 'b' is released. | |
| } | |
| Attribute 'cf_consumed' (Clang-specific) | |
| ---------------------------------------- | |
| The 'cf_consumed' attribute is practically identical to ns_consumed_. The | |
| attribute can be placed on a specific parameter in either the declaration of a | |
| function or an Objective-C method. It indicates to the static analyzer that the | |
| object reference is implicitly passed to a call to ``CFRelease`` upon | |
| completion of the call to the given function or method. The CoreFoundation | |
| framework defines a macro ``CF_RELEASES_ARGUMENT`` that is functionally | |
| equivalent to the ``CF_CONSUMED`` macro shown below. | |
| Operationally this attribute is nearly identical to 'ns_consumed'. | |
| **Example** | |
| .. code-block:objc | |
| #ifndef __has_feature // Optional. | |
| #define __has_feature(x) 0 // Compatibility with non-clang compilers. | |
| #endif | |
| #ifndef CF_CONSUMED | |
| #if __has_feature(attribute_cf_consumed) | |
| #define CF_CONSUMED __attribute__((cf_consumed)) | |
| #else | |
| #define CF_CONSUMED | |
| #endif | |
| #endif | |
| void consume_cf(id CF_CONSUMED x); | |
| void consume_CFDate(CFDateRef CF_CONSUMED x); | |
| void test() { | |
| id x = [[NSObject alloc] init]; | |
| consume_cf(x); // No leak! | |
| } | |
| void test2() { | |
| CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); | |
| consume_CFDate(date); // No leak, including under GC! | |
| } | |
| @interface Foo : NSObject | |
| + (void) releaseArg:(CFDateRef) CF_CONSUMED x; | |
| @end | |
| void test_method() { | |
| CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); | |
| [Foo releaseArg:date]; // No leak! | |
| } | |
| .. _ns_consumes_self: | |
| Attribute 'ns_consumes_self' (Clang-specific) | |
| --------------------------------------------- | |
| The 'ns_consumes_self' attribute can be placed only on an Objective-C method | |
| declaration. It indicates that the receiver of the message is | |
| "consumed" (a single reference count decremented) after the message | |
| is sent. This matches the semantics of all "init" methods. | |
| One use of this attribute is declare your own init-like methods that do not | |
| follow the standard Cocoa naming conventions. | |
| **Example** | |
| .. code-block:objc | |
| #ifndef __has_feature | |
| #define __has_feature(x) 0 // Compatibility with non-clang compilers. | |
| #endif | |
| #ifndef NS_CONSUMES_SELF | |
| #if __has_feature((attribute_ns_consumes_self)) | |
| #define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) | |
| #else | |
| #define NS_CONSUMES_SELF | |
| #endif | |
| #endif | |
| @interface MyClass : NSObject | |
| - initWith:(MyClass *)x; | |
| - nonstandardInitWith:(MyClass *)x NS_CONSUMES_SELF NS_RETURNS_RETAINED; | |
| @end | |
| In this example, ``-nonstandardInitWith:`` has the same ownership | |
| semantics as the init method ``-initWith:``. The static analyzer will | |
| observe that the method consumes the receiver, and then returns an object with | |
| a +1 retain count. | |
| The Foundation framework defines a macro ``NS_REPLACES_RECEIVER`` which is | |
| functionally equivalent to the combination of ``NS_CONSUMES_SELF`` and | |
| ``NS_RETURNS_RETAINED`` shown above. | |
| Libkern Memory Management Annotations | |
| ##################################### | |
| `Libkern <https://developer.apple.com/documentation/kernel/osobject?language=objc>`_ | |
| requires developers to inherit all heap allocated objects from ``OSObject`` and | |
| to perform manual reference counting. The reference counting model is very | |
| similar to MRR (manual retain-release) mode in | |
| `Objective-C <https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html>`_ | |
| or to CoreFoundation reference counting. | |
| Freshly-allocated objects start with a reference count of 1, and calls to | |
| ``retain`` increment it, while calls to ``release`` decrement it. The object is | |
| deallocated whenever its reference count reaches zero. | |
| Manually incrementing and decrementing reference counts is error-prone: | |
| over-retains lead to leaks, and over-releases lead to uses-after-free. | |
| The analyzer can help the programmer to check for unbalanced | |
| retain/release calls. | |
| The reference count checking is based on the principle of *locality*: it should | |
| be possible to establish correctness (lack of leaks/uses after free) by looking | |
| at each function body, and the declarations (not the definitions) of all the | |
| functions it interacts with. | |
| In order to support such reasoning, it should be possible to *summarize* the | |
| behavior of each function, with respect to reference count of its returned | |
| values and attributes. | |
| By default, the following summaries are assumed: | |
| - All functions starting with ``get`` or ``Get``, unless they are returning | |
| subclasses of ``OSIterator``, are assumed to be returning at +0. That is, the | |
| caller has no reference count *obligations* with respect to the reference | |
| count of the returned object and should leave it untouched. | |
| - All other functions are assumed to return at +1. That is, the caller has an | |
| *obligation* to release such objects. | |
| - Functions are assumed not to change the reference count of their parameters, | |
| including the implicit ``this`` parameter. | |
| These summaries can be overriden with the following | |
| `attributes <https://clang.llvm.org/docs/AttributeReference.html#os-returns-not-retained>`_: | |
| Attribute 'os_returns_retained' | |
| ------------------------------- | |
| The ``os_returns_retained`` attribute (accessed through the macro | |
| ``LIBKERN_RETURNS_RETAINED``) plays a role identical to `ns_returns_retained`_ | |
| for functions returning ``OSObject`` subclasses. The attribute indicates that | |
| it is a callers responsibility to release the returned object. | |
| Attribute 'os_returns_not_retained' | |
| ----------------------------------- | |
| The ``os_returns_not_retained`` attribute (accessed through the macro | |
| ``LIBKERN_RETURNS_NOT_RETAINED``) plays a role identical to | |
| `ns_returns_not_retained`_ for functions returning ``OSObject`` subclasses. The | |
| attribute indicates that the caller should not change the retain count of the | |
| returned object. | |
| **Example** | |
| .. code-block:objc | |
| class MyClass { | |
| OSObject *f; | |
| LIBKERN_RETURNS_NOT_RETAINED OSObject *myFieldGetter(); | |
| } | |
| // Note that the annotation only has to be applied to the function declaration. | |
| OSObject * MyClass::myFieldGetter() { | |
| return f; | |
| } | |
| Attribute 'os_consumed' | |
| ----------------------- | |
| Similarly to `ns_consumed`_ attribute, ``os_consumed`` (accessed through | |
| ``LIBKERN_CONSUMED``) attribute, applied to a parameter, indicates that the | |
| call to the function *consumes* the parameter: the callee should either release | |
| it or store it and release it in the destructor, while the caller should assume | |
| one is subtracted from the reference count after the call. | |
| .. code-block:objc | |
| IOReturn addToList(LIBKERN_CONSUMED IOPMinformee *newInformee); | |
| Attribute 'os_consumes_this' | |
| ---------------------------- | |
| Similarly to `ns_consumes_self`_, the ``os_consumes_self`` attribute indicates | |
| that the method call *consumes* the implicit ``this`` argument: the caller | |
| should assume one was subtracted from the reference count of the object after | |
| the call, and the callee has on obligation to either release the argument, or | |
| store it and eventually release it in the destructor. | |
| .. code-block:objc | |
| void addThisToList(OSArray *givenList) LIBKERN_CONSUMES_THIS; | |
| Out Parameters | |
| -------------- | |
| A function can also return an object to a caller by a means of an out parameter | |
| (a pointer-to-OSObject-pointer is passed, and a callee writes a pointer to an | |
| object into an argument). Currently the analyzer does not track unannotated out | |
| parameters by default, but with annotations we distinguish four separate cases: | |
| **1. Non-retained out parameters**, identified using | |
| ``LIBKERN_RETURNS_NOT_RETAINED`` applied to parameters, e.g.: | |
| .. code-block:objc | |
| void getterViaOutParam(LIBKERN_RETURNS_NOT_RETAINED OSObject **obj) | |
| Such functions write a non-retained object into an out parameter, and the | |
| caller has no further obligations. | |
| **2. Retained out parameters**, identified using ``LIBKERN_RETURNS_RETAINED``: | |
| .. code-block:objc | |
| void getterViaOutParam(LIBKERN_RETURNS_NOT_RETAINED OSObject **obj) | |
| In such cases a retained object is written into an out parameter, which the caller has then to release in order to avoid a leak. | |
| These two cases are simple - but in practice a functions returning an | |
| out-parameter usually also return a return code, and then an out parameter may | |
| or may not be written, which conditionally depends on the exit code, e.g.: | |
| .. code-block:objc | |
| bool maybeCreateObject(LIBKERN_RETURNS_RETAINED OSObject **obj); | |
| For such functions, the usual semantics is that an object is written into on "success", and not written into on "failure". | |
| For ``LIBKERN_RETURNS_RETAINED`` we assume the following definition of | |
| success: | |
| - For functions returning ``OSReturn`` or ``IOReturn`` (any typedef to | |
| ``kern_return_t``) success is defined as having an output of zero | |
| (``kIOReturnSuccess`` is zero). | |
| - For all others, success is non-zero (e.g. non-nullptr for pointers) | |
| **3. Retained out parameters on zero return** The annotation | |
| ``LIBKERN_RETURNS_RETAINED_ON_ZERO`` states that a retained object is written | |
| into if and only if the function returns a zero value: | |
| .. code-block:objc | |
| bool OSUnserializeXML(void *data, LIBKERN_RETURNS_RETAINED_ON_ZERO OSString **errString); | |
| Then the caller has to release an object if the function has returned zero. | |
| **4. Retained out parameters on non-zero return** Similarly, | |
| ``LIBKERN_RETURNS_RETAINED_ON_NONZERO`` specifies that a retained object is | |
| written into the parameter if and only if the function has returned a non-zero | |
| value. | |
| Note that for non-retained out parameters conditionals do not matter, as the | |
| caller has no obligations regardless of whether an object is written into or | |
| not. |