[clang] [BoundsSafety][Sema] Allow counted_by and counted_by_or_null on pointers where the pointee type is incomplete but potentially completable (PR #106321)

via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 24 23:06:46 PDT 2024


================
@@ -0,0 +1,584 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -fsyntax-only -verify %s
+
+#define __counted_by(f)  __attribute__((counted_by(f)))
+
+// =============================================================================
+// # Struct incomplete type with attribute in the decl position
+// =============================================================================
+
+// Note: This could be considered misleading. The typedef isn't actually on this
+// line. Also note the discrepancy in diagnostic count (27 vs 51) is due to
+// the pointer arithmetic on incomplete pointee type diagnostic always using
+// diagnostic text that refers to the underlying forward decl, even when the
+// typedef is used.
+// expected-note at +1 27{{forward declaration of 'Incomplete_t' (aka 'struct IncompleteTy')}}
+struct IncompleteTy; // expected-note 51{{forward declaration of 'struct IncompleteTy'}}
+
+typedef struct IncompleteTy Incomplete_t; 
+
+struct CBBufDeclPos {
+  int count;
+  struct IncompleteTy* buf __counted_by(count); // OK expected-note 27{{__counted_by attribute is here}}
+  Incomplete_t* buf_typedef __counted_by(count); // OK expected-note 27{{__counted_by attribute is here}}
+};
+
+void consume_struct_IncompleteTy(struct IncompleteTy* buf);
+
+int idx(void);
+
+
+
+void test_CBBufDeclPos(struct CBBufDeclPos* ptr) {
+  // ===========================================================================
+  // ## Local variable initialization
+  // ===========================================================================
+  struct CBBufDeclPos explicit_desig_init = {
+    .count = 0,
+    // expected-error at +1{{cannot initialize 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}}
+    .buf = 0x0,
+    // expected-error at +1{{cannot initialize 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}}
+    .buf_typedef = 0x0
+  };
+  // Variable is not currently marked as invalid so uses of the variable allows
+  // diagnostics to fire.
+  // expected-error at +1{{cannot assign to 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}}
+  explicit_desig_init.buf = 0x0;
+  // expected-error at +1{{cannot assign to 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}}
+  explicit_desig_init.buf_typedef = 0x0;
+  // expected-error at +1{{cannot use 'explicit_desig_init.buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}}
+  void *tmp = explicit_desig_init.buf;
+  // expected-error at +1{{cannot use 'explicit_desig_init.buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}}
----------------
Sirraide wrote:

That is... a long diagnostic. I do think the explanation has value because this is probably not obvious to users not familiar w/ this attribute (which is probably most users), but it’s also nice to be able to get a general idea of what is wrong just from a shorter message.

Maybe we could make the main error something like ‘Access to bounds-checked field has incomplete type’, and then move the rest of the explanation into a note (we could merge this note with the one that points to the `__counted_by` attribute)?

The same also applies to the other long diagnostic below (which iirc is just the same diagnostic because of `%select`).

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


More information about the cfe-commits mailing list