In case, this may be a useful data point for anyone, guarded_by (which is an 
attribute used in C and C++, while it’s currently used more in C++) already 
accepts relatively more complex expressions as operands, like `&id`, 
`foo()->get_lock()`, `system->machine_lock`, and `*obj`. And it uses forward 
referencing + member name lookup in structure. Here is an example of C code 
that does that:  
https://github.com/Hiimsonkul/blink/blob/7fa43c6d8e90acf2a966a9da480e884536b2b79d/blink/machine.h#L231

Cheers,
Yeoul

> On Jul 28, 2025, at 11:18 AM, Yeoul Na <yeoul...@apple.com> wrote:
> 
> 
> 
>> On Jul 28, 2025, at 10:27 AM, Qing Zhao <qing.z...@oracle.com> wrote:
>> 
>> 
>> 
>>> On Jul 26, 2025, at 12:43, Yeoul Na <yeoul...@apple.com> wrote:
>>> 
>>> 
>>> 
>>>> On Jul 24, 2025, at 3:52 PM, Kees Cook <k...@kernel.org> wrote:
>>>> 
>>>> On Thu, Jul 24, 2025 at 04:26:12PM +0000, Aaron Ballman wrote:
>>>>> Ah, apologies, I wasn't clear. My thinking is: we're (Clang folks)
>>>>> going to want it to work in C++ mode because of shared headers. If it
>>>>> works in C++ mode, then we have to figure out what it means with all
>>>>> the various C++ features that are possible, not just the use cases
>>>> 
>>>> I am most familiar with C, so I may be missing something here, but if
>>>> -fbounds-safety is intended to be C only, then why not just make it
>>>> unrecognized in C++?
>>> 
>>> The bounds safety annotations must also be parsable in C++. While C++ can 
>>> get bounds checking by using std::span instead of raw pointers, switching 
>>> to std::span breaks ABI. Therefore, in many situations, C++ code must 
>>> continue to use raw pointers—for example, when interoperating with C code 
>>> by sharing headers with C. In such cases, bounds annotations can help close 
>>> safety gaps in raw pointers.
>> 
>> -fbound-safety feature was initially proposed as an C extension, So, it’s 
>> natural to make it compatible with C language, not C++. 
>> If C++ also need such a feature, then an extension to C++ is needed too.
>> If a consistent syntax for this feature can satisfy both C and C++,  that 
>> will be ideal.
>> However, if  providing such consistent syntax requires major changes to C 
>> language, 
>> ( a new name lookup scope, and late parsing), it might be a good idea to 
>> provide different syntax for C and C++. 
> 
> So the main problem here is when the "same code” will be parsed in both in C 
> and C++, which is quite common in practice.
> 
> Therefore, we need a way to reasonably write code that works both C and C++. 
> 
> From my perspective, that means:
> 
> 1. The same spelling doesn’t “silently" behave differently in C and C++.
> 2. At least the most common use cases (i.e., __counted_by(peer)) should be 
> able to be written the same way in C and C++, without ceremony.
> 
> Here is our compromise proposal that meets these requirements, until we get 
> blessing from the standard for a more elegant solution:
> 
> 1. `__counted_by(member)` keeps working as is: late parsing + name lookup 
> finds the member name first
> 2. `__counted_by_expr(expr)` uses a new syntax (e.g., __self), and is not 
> allowed to use a name that matches the member name without the new syntax 
> even if that would’ve resolved to a global variable. Use something like  
> `__global_ref(id)` to disambiguate. This rule will prevent the confusion 
> where `__counted_by_expr(id)` and `__counted_by(id)` may designate different 
> entities.
> 
> Here are the examples:
> 
> Ex 1)
> constexpr int n = 10;
> 
> struct s {
>   int *__counted_by(n) ptr; // resolves to member `n`; which matches the 
> current behavior 
>   int n;
> };
> 
> Ex 2)
> constexpr int n = 10;
> struct s {
>   int *__counted_by_expr(n) ptr; // error: referring to a member name without 
> “__self."
>   int n;
> };
> 
> Ex 3)
> constexpr int n = 10;
> struct s {
>   int *__counted_by_expr(__self.n) ptr; // resolves to member `n`
>   int n;
> };
> 
> 
> Ex 4)
> constexpr int n = 10;
> struct s {
>   int *__counted_by_expr(__self.n + 1) ptr; // resolves to member `n`
>   int n;
> };
> 
> 
> Ex 5)
> constexpr int n = 10;
> struct s {
>   int *__counted_by_expr(__global_ref(n) + 1) ptr; // resolves to global `n`
>   int n;
> };
> 
> 
> Ex 6)
> constexpr int n = 10;
> struct s {
>   int *__counted_by_expr(n + 1) ptr; // resolves to global `n`; okay, no 
> matching member name
> };
> 
> Or in case, people prefer forward declaration inside `__counted_by_expr()`, 
> the similar rule can apply to achieve the same goal.
> 
> Yeoul
> 
>> 
>> Qing
>>> 
>>> Yeoul
>>> 
>>> 
>>>> Shared headers don't seem like much of a challenge;
>>>> e.g. Linux uses macros specifically to avoid mixing illegal syntax into
>>>> places where it isn't supported. For example, why can't Clang have:
>>>> 
>>>> #if defined(__cplusplus)
>>>> # define __counted_by(ARGS...)
>>>> #else
>>>> # define __counted_by(ARGS...) __attribute__((counted_by(ARGS)))
>>>> #endif
>>>> 
>>>> And then use __counted_by() in all the shared headers? C++ uses will
>>>> ignore it, and C uses will apply the attributes.
>>>> 
>>>> It seems weird to me that Clang needs to solve how -fbounds-safety works
>>>> with C++ if it's not for _use_ in C++. I feel like I'm missing something
>>>> about features that can't be macro-ified or some ABI issue, but I keep
>>>> coming up empty.
>>>> 
>>>> -- 
>>>> Kees Cook

Reply via email to