================
@@ -9971,6 +10035,153 @@ requirement:
}];
}
+def SizedByDocs : Documentation {
+ let Category = DocCatField;
+ let Heading = "sized_by";
+ let Content = [{
+The ``sized_by`` attribute is applied to a pointer to indicate that the pointer
+points to memory containing at least the number of *bytes* given by the
+attribute's argument. It is closely related to ``counted_by``; the difference
is
+that ``counted_by`` counts the number of *elements* of the pointee type,
whereas
+``sized_by`` counts the number of *bytes*. This makes ``sized_by`` the natural
+choice for ``void *`` and other byte buffers.
+
+This attribute is used by `-fbounds-safety <BoundsSafety.html>`__ to propagate
+bounds information on API surfaces without any ABI changes. This attribute is
+also used to improve the results of the array bound sanitizer and the
+``__builtin_dynamic_object_size`` builtin.
+
+The argument is an expression of integer type, following the same rules as the
+argument of ``counted_by``. Unlike ``counted_by``, ``sized_by`` cannot be
+applied to a C99 flexible array member; it applies to pointers only. For
+example:
+
+.. code-block:: c
+
+ struct object {
+ unsigned long size;
+ void *data __attribute__((sized_by(size)));
+ };
+
+A pointer annotated with ``sized_by`` must have a size of zero when it is null.
+This requirement is currently only enforced when compiling with
+`-fbounds-safety <BoundsSafety.html>`__. Use ``sized_by_or_null`` for a pointer
+that may be null while carrying a nonzero size.
+
+Keeping pointer and size in sync
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``sized_by`` attribute establishes a relationship between the annotated
+pointer and its size: the pointer must point to at least ``size`` bytes.
+Assigning to only one of them can break this relationship.
+Without `-fbounds-safety <BoundsSafety.html>`__, it is the programmer's
+responsibility to ensure the pointer and size remain in sync. With
+``-fbounds-safety`` it is automatically enforced. For example:
+
+.. code-block:: c
+
+ struct buffer {
+ uint8_t *buf __attribute__((sized_by(size)));
+ size_t size;
+ };
+
+ void grow(struct buffer *b, size_t new_size) {
+ // b->buf isn't updated. The underlying memory pointed to by b->buf might
be
+ // smaller than new_size which would contradict the sized_by attribute.
+ // Compile error with -fbounds-safety but allowed without -fbounds-safety.
+ b->size = new_size;
+ }
+
+Updating both together - so that ``buf`` points to ``size`` bytes - keeps
+the attribute true. For example:
+
+.. code-block:: c
+
+ void grow(struct buffer *b, size_t new_size) {
+ // Allowed by -fbounds-safety
+ uint8_t *new_buf = malloc(new_size);
+ // -fbounds-safety enforces that the `new_buf` points to at least
`new_size`
+ // bytes at runtime. Without -fbounds-safety nothing enforces this.
+ b->buf = new_buf;
+ b->size = new_size;
+ }
+
+Incomplete and variable-length pointees
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``sized_by`` is typically applied to ``void *`` or a pointer to a byte-sized
+type, but it may be used with any pointee type. Two situations call for this,
+both of which rule out counting fixed-size elements:
+
+First, the pointee type may be incomplete, such as an opaque type. Its element
+size is then unavailable, so ``counted_by`` cannot be used, whereas
``sized_by``
+bounds the memory in bytes and imposes no completeness requirement.
+
+Second, the buffer may hold variable-length elements, so there is no fixed
+element size to count, even though the total byte size is well defined. For
+example, a buffer might pack together several structures that each end in a
+flexible array member of differing length:
+
+.. code-block:: c
+
+ struct var_len {
+ int fam_size;
+ char data[] __attribute__((counted_by(fam_size)));
+ };
+
+ struct buffer_view {
+ int byte_size;
+ struct var_len *buf __attribute__((sized_by(byte_size)));
+ };
+
+Here ``counted_by`` cannot be applied to ``buf`` because its pointee is a
+variable-length structure, but ``sized_by`` bounds the whole region in bytes;
+the region is traversed by advancing a byte offset rather than by indexing
+elements.
+ }];
+}
+
+def CountedByOrNullDocs : Documentation {
+ let Category = DocCatField;
+ let Heading = "counted_by_or_null";
+ let Content = [{
+The ``counted_by_or_null`` attribute is applied to a pointer to indicate that,
+if the pointer is non-null, it points to memory containing at least the number
+of *elements* given by the attribute's argument. If the pointer is null, the
+value of the argument is ignored and the pointer points to zero elements.
+
+The ``counted_by_or_null`` attribute is identical to ``counted_by`` except that
+it treats null pointers differently and cannot be applied to a flexible array
+member. Whereas ``counted_by`` requires a null pointer to have a count of zero,
+``counted_by_or_null`` allows the pointer to be null regardless of the value of
+the count. This supports the common idiom where a pointer is either null or
+points to memory containing at least the given number of elements.
----------------
delcypher wrote:
These are great examples. The reason I didn't mention things like this is
because in upstream Clang those attributes aren't accepted on function return
types or parameter types yet. Currently they are only supported member pointers
in structs and FAM pointers in structs.
I think it would be confusing to write these examples if the Clang that ships
with this documentation doesn't accept them.
https://github.com/llvm/llvm-project/pull/212877
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits