[clang] [analyzer] Report violations of the "returns_nonnull" attribute (PR #106048)

DonĂ¡t Nagy via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 27 02:28:35 PDT 2024


================
@@ -10,3 +12,42 @@ void block_arity_mismatch() {
   void(^b)() = ^(int a, int b) { };
   b(1);  // no-crash expected-warning {{Block taking 2 arguments is called with fewer (1)}}
 }
+
+int *nonnull_return_annotation_indirect() __attribute__((returns_nonnull));
+int *nonnull_return_annotation_indirect() {
+  int *x = 0;
+  return x; // expected-warning {{Null returned from a function that is expected to return a non-null value}}
+}
+
+int *nonnull_return_annotation_direct() __attribute__((returns_nonnull));
+int *nonnull_return_annotation_direct() {
+  return 0; // expected-warning {{Null returned from a function that is expected to return a non-null value}}
+} // expected-warning at -1 {{null returned from function that requires a non-null return value}}
+
+int *nonnull_return_annotation_assumed() __attribute__((returns_nonnull));
+int *nonnull_return_annotation_assumed(int* ptr) {
+  if (ptr) {
+    return ptr;
+  }
+  return ptr; // expected-warning {{Null returned from a function that is expected to return a non-null value}}
+}
+
+int *produce_nonnull_ptr() __attribute__((returns_nonnull));
+
+__attribute__((returns_nonnull))
+int *cannot_return_null() {
+  int *x = produce_nonnull_ptr();
+  if (!x) {
+    clang_analyzer_warnIfReached();
+    // Incorrect: expected-warning at -1 {{REACHABLE}}
+    // According to produce_nonnull_ptr contract, x cannot be null.
+  }
+  // Regardless of the potential state split above, x cannot be nullptr
+  // according to the produce_nonnull_ptr annotation.
+  return x;
+  // False positive: expected-warning at -1 {{Null returned from a function that is expected to return a non-null value}}
+}
+
+__attribute__((returns_nonnull)) int *passthrough(int *p) {
+  return p; // no-warning: we have no evidence that `p` is null, i.e., violating the contract
+}
----------------
NagyDonat wrote:

If the tests within `nullability.mm` still pass (expect for the over-suppression one), then there is no need to preserve that suppression.

I'd say that it's OK to lift the suppression within this commit, but add a remark like "This commit also reverts an old hack introduced by 49bd58f1ebe28d97e4949e9c757bc5dfd8b2d72f because it is no longer needed." to the commit message. (Perhaps putting it into a separate commit would be _slightly_ more elegant, but I don't think that it would produce real practical benefits.)

https://github.com/llvm/llvm-project/pull/106048


More information about the cfe-commits mailing list