Szelethus created this revision.
Szelethus added reviewers: NoQ, steakhal, donat.nagy, balazske, gamesh411.
Herald added subscribers: manas, ASDenysPetrov, martong, dkrupp, 
mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun, yaxunl.
Herald added a reviewer: aaron.ballman.
Herald added a project: All.
Szelethus requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Pretty much what it says on the tin! I worked a bunch on this checker so I had 
some vague memory (hehe) what these annotations mean, and also found this 
thread in the mailing list:
https://discourse.llvm.org/t/ownership-attribute-for-malloc-etc-checking/16260


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D156787

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  clang/test/Analysis/malloc-annotations.c

Index: clang/test/Analysis/malloc-annotations.c
===================================================================
--- clang/test/Analysis/malloc-annotations.c
+++ clang/test/Analysis/malloc-annotations.c
@@ -148,6 +148,12 @@
   return p; // no-warning
 }
 
+void af6(void) {
+  int *p = my_malloc(12);
+  my_hold(p);
+  *p = 4;
+}
+
 
 
 // This case tests that storing malloc'ed memory to a static variable which is
Index: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1776,6 +1776,8 @@
   if (!State)
     return nullptr;
 
+  // TODO: Check the attribute docs in AttrDocs.td, it states that only malloc
+  // is accepted. Please adjust if we start supporting "new".
   if (Att->getModule()->getName() != "malloc")
     return nullptr;
 
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -1164,6 +1164,60 @@
   }];
 }
 
+def OwnershipDocs : Documentation {
+  let Category = DocCatFunction;
+  let Heading = "ownership_holds, ownership_returns, ownership_takes";
+  let Content = [{
+These attributes help the static analyzer understand custom ownership management
+functions. Neither of these affect the generated binary in any way, its only
+meant to assist the Clang Static Analyzer. You can use these annotations if your
+code uses wrapper functions around ``malloc`` or ``free``, or uses functions
+that take over ownership altogether.
+
+All 3 annotations have two parameters: the first is type of allocator used to
+allocate the memory (as of writing, the only accepted value is ``malloc``, but
+we intend to recognize ``new`` as well). We use this to check whether the
+correct deallocator is used. The second is an integer value.
+
+.. code-block:: c
+
+  void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+  void *__attribute((ownership_returns(malloc, 1))) my_malloc(size_t);
+  void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
+
+``onwership_returns``: Functions with this annotation return dynamic memory.
+The second annotation parameter is the size of the returned memory in bytes.
+
+``ownership_takes``: Functions with this annotation deallocate one of the
+function parameters. The second annotation parameter is the index of the
+function parameter to deallocate.
+
+``ownership_holds``: Functions with this annotation take over the ownership of
+one of the parameters. The static analyzer doesn't assume it to be deallocated
+immediately, but assumes that it will be before the end of the program. The
+second annotation parameter is the index of the function parameter to take hold
+of.
+
+.. code-block:: c
+
+  void foobar() {
+    int *p = my_malloc(sizeof(int));
+  } // warn: Memory leak
+
+  void foo() {
+    int *p = my_malloc(sizeof(int));
+    my_free(p);
+    free(p); // warn: Attempt to free released memory
+  }
+
+  void bar() {
+    int *p = my_malloc(sizeof(int));
+    my_hold(p);
+    *p = 4; // no warn: Pointer is not released
+  } // no warn: Ownership is transferred and assumed to have not escaped
+  }];
+}
+
 def ObjCMethodFamilyDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -2355,7 +2355,7 @@
   let Args = [IdentifierArgument<"Module">,
               VariadicParamIdxArgument<"Args">];
   let Subjects = SubjectList<[HasFunctionProto]>;
-  let Documentation = [Undocumented];
+  let Documentation = [OwnershipDocs];
 }
 
 def Packed : InheritableAttr {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to