Skip to content

Commit

Permalink
[NFC][analyzer][docs] Document MallocChecker's ownership attributes (l…
Browse files Browse the repository at this point in the history
…lvm#121759)

Exactly what it says on the tin! These were written ages ago (2010s),
but are still functional, only the docs are missing.


![image](https://github.com/user-attachments/assets/d6b89611-4064-41dd-8482-8643e9e68836)

---------

Co-authored-by: Donát Nagy <donat.nagy@ericsson.com>
Co-authored-by: Balazs Benics <benicsbalazs@gmail.com>
Co-authored-by: isuckatcs <65320245+isuckatcs@users.noreply.github.com>
  • Loading branch information
4 people authored Jan 7, 2025
1 parent 5514865 commit 7ce15f3
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2776,7 +2776,7 @@ def Ownership : InheritableAttr {
let Args = [IdentifierArgument<"Module">,
VariadicParamIdxArgument<"Args">];
let Subjects = SubjectList<[HasFunctionProto]>;
let Documentation = [Undocumented];
let Documentation = [OwnershipDocs];
}

def Packed : InheritableAttr {
Expand Down
75 changes: 75 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,81 @@ Query for this attribute with ``__has_attribute(overloadable)``.
}];
}

def OwnershipDocs : Documentation {
let Heading = "ownership_holds, ownership_returns, ownership_takes (Clang "
"Static Analyzer)";
let Category = DocCatFunction;
let Content = [{

.. note::

In order for the Clang Static Analyzer to acknowledge these attributes, the
``Optimistic`` config needs to be set to true for the checker
``unix.DynamicMemoryModeling``:

``-Xclang -analyzer-config -Xclang unix.DynamicMemoryModeling:Optimistic=true``

These attributes are used by the Clang Static Analyzer's dynamic memory modeling
facilities to mark custom allocating/deallocating functions.

All 3 attributes' first parameter of type string is the type of the allocation:
``malloc``, ``new``, etc. to allow for catching :ref:`mismatched deallocation
<unix-MismatchedDeallocator>` bugs. The allocation type can be any string, e.g.
a function annotated with
returning a piece of memory of type ``lasagna`` but freed with a function
annotated to release ``cheese`` typed memory will result in mismatched
deallocation warning.

The (currently) only allocation type having special meaning is ``malloc`` --
the Clang Static Analyzer makes sure that allocating functions annotated with
``malloc`` are treated like they used the standard ``malloc()``, and can be
safely deallocated with the standard ``free()``.

* Use ``ownership_returns`` to mark a function as an allocating function. Takes
1 parameter to denote the allocation type.
* Use ``ownership_takes`` to mark a function as a deallocating function. Takes 2
parameters: the allocation type, and the index of the parameter that is being
deallocated (counting from 1).
* Use ``ownership_holds`` to mark that a function takes over the ownership of a
piece of memory and will free it at some unspecified point in the future. Like
``ownership_takes``, this takes 2 parameters: the allocation type, and the
index of the parameter whose ownership will be taken over (counting from 1).

The annotations ``ownership_takes`` and ``ownership_holds`` both prevent memory
leak reports (concerning the specified argument); the difference between them
is that using taken memory is a use-after-free error, while using held memory
is assumed to be legitimate.

Example:

.. code-block:: c

// Denotes that my_malloc will return with a dynamically allocated piece of
// memory using malloc().
void __attribute((ownership_returns(malloc))) *my_malloc(size_t);

// Denotes that my_free will deallocate its parameter using free().
void __attribute((ownership_takes(malloc, 1))) my_free(void *);

// Denotes that my_hold will take over the ownership of its parameter that was
// allocated via malloc().
void __attribute((ownership_holds(malloc, 1))) my_hold(void *);

Further reading about dynamic memory modeling in the Clang Static Analyzer is
found in these checker docs:
:ref:`unix.Malloc <unix-Malloc>`, :ref:`unix.MallocSizeof <unix-MallocSizeof>`,
:ref:`unix.MismatchedDeallocator <unix-MismatchedDeallocator>`,
:ref:`cplusplus.NewDelete <cplusplus-NewDelete>`,
:ref:`cplusplus.NewDeleteLeaks <cplusplus-NewDeleteLeaks>`,
:ref:`optin.taint.TaintedAlloc <optin-taint-TaintedAlloc>`.
Mind that many more checkers are affected by dynamic memory modeling changes to
some extent.

Further reading for other annotations:
`Source Annotations in the Clang Static Analyzer <https://clang-analyzer.llvm.org/annotations.html>`_.
}];
}

def ObjCMethodFamilyDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down

0 comments on commit 7ce15f3

Please sign in to comment.