[clang] Specify taking address of a variable referred to by '__counted_by' is forbidden (PR #106147)

Yeoul Na via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 26 14:39:53 PDT 2024


https://github.com/rapidsna created https://github.com/llvm/llvm-project/pull/106147

`-fbounds-safety` doesn't allow taking address of a variable referred to by `__counted_by`, in order to prevent code from using the pointer to update the variable without necessary checks to keep the invariant of `__counted_by`.

As shown in the example below, with -fbounds-safety the compiler ensures that the `__counted_by` pointer/or array has at least as many as elements that the attribute indicates, by requiring the count and the buf are always updated side by side and emitting run-time checks to ensure the new values are valid.

```
struct counted_buf {
  sized_t count;
  int *__counted_by(count) buf;
};

// BEFORE FIX
void foo(struct counted_buf *p) {
  p->count = 10; // error: assignment to 'count' requires corresponding assignment to 'int *__counted_by(count) buf')
}

// FIXED by adding assignment to `p->buf`
void foo(struct counted_buf *p) {
  // The compiler is now happy because  
  p->buf = (int *)malloc(sizeof(int) *5); // run-time checks are emitted to make sure new buf has at least `10` elements. 
  p->count = 10;
}
```

Consequently, `-fbounds-safety` prevents taking address of a variable referred to by `__counted_by`, because otherwise, the compiler cannot check the updates through the pointer pointing to the count:

```
void foo(struct counted_buf *p) {
  int *count_p = &p->count; // error: variable referred to by '__counted_by' cannot be pointed to by any other variable
 *count_p = 10; // without the above error, `count_p` is a normal `int *` so the compiler cannot check the value it updates against `__counted_by`
}
```

This PR is to explicitly specify this restriction and avoid future conflicts.

>From 8ed704c9e85b917d526df1e468e325a302f5a4d2 Mon Sep 17 00:00:00 2001
From: Yeoul Na <yeoul_na at apple.com>
Date: Mon, 26 Aug 2024 14:17:59 -0700
Subject: [PATCH] Specify taking address of a variable referred to by
 '__counted_by' is forbidden

---
 clang/docs/BoundsSafety.rst | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/clang/docs/BoundsSafety.rst b/clang/docs/BoundsSafety.rst
index 8fd655663edb00..e4ddd3c62db65d 100644
--- a/clang/docs/BoundsSafety.rst
+++ b/clang/docs/BoundsSafety.rst
@@ -759,7 +759,24 @@ relationship must hold even after any of these related variables are updated. To
 this end, the model requires that assignments to ``buf`` and ``count`` must be
 side by side, with no side effects between them. This prevents ``buf`` and
 ``count`` from temporarily falling out of sync due to updates happening at a
-distance.
+distance. In addition, taking address of ``count`` is not allowed in order to 
+prevent the programmers from updating the ``count`` through the pointer, which
+will evade the necessary checks to make ``count`` and ``buf`` in sync.
+
+.. code-block:: c
+
+   struct counted_buf {
+      int *__counted_by(count) buf;
+      size_t count;
+   };
+
+   void foo(struct counted_buf *p) {
+      int *pointer_to_count = &p->count; // error: variable referred to by
+      // '__counted_by' cannot be pointed to by any other variable; exception is
+      // when the pointer is passed as a compatible argument to a function.
+      *pointer_to_count = SIZE_MAX; // Without reporting the error above, the
+      // compiler cannot prevent count from getting an invalid value.   
+   }
 
 The example below shows a function ``alloc_buf`` that initializes a struct that
 members that use the ``__counted_by`` annotation. The compiler allows these



More information about the cfe-commits mailing list