Now, if 1. __builtin_get_counted_by should return a LVALUE instead of a pointer (required by CLANG’s design) And 2. It’s better not to change the behavior of __builtin_choose_expr.
Then the solution left is: __builtin_get_counted_by (p->FAM) returns a LVALUE as p->COUNT if p->FAM has a counted_by attribute, if p->FAM does not have a counted_by attribute, silently do nothing. (Or just issue warning if Linux is OKEY with such waning). Is this acceptable? thanks. Qing > On Sep 6, 2024, at 16:59, Bill Wendling <isanb...@gmail.com> wrote: > > On Fri, Sep 6, 2024 at 12:32 PM Martin Uecker <ma.uec...@gmail.com> wrote: >> >> Am Freitag, dem 06.09.2024 um 13:59 +0000 schrieb Qing Zhao: >>> >>>> On Sep 5, 2024, at 18:22, Bill Wendling <isanb...@gmail.com> wrote: >>>> >>>> Hi Qing, >>>> >>>> Sorry for my late reply. >>>> >>>> On Thu, Aug 29, 2024 at 7:22 AM Qing Zhao <qing.z...@oracle.com> wrote: >>>>> >>>>> Hi, >>>>> >>>>> Thanks for the information. >>>>> >>>>> Yes, providing a unary operator similar as __counted_by(PTR) as suggested >>>>> by multiple people previously is a cleaner approach. >>>>> >>>>> Then the programmer will use the following: >>>>> >>>>> __builtin_choose_expr( >>>>> __builtin_has_attribute (__p->FAM, "counted_by”) >>>>> __builtin_get_counted_by(__p->FAM) = COUNT, 0); >>>>> >>>>> From the programmer’s point of view, it’s cleaner too. >>>>> >>>>> However, there is one issue with “__builtin_choose_expr” currently in >>>>> GCC, its documentation explicitly mentions this limitation: >>>>> (https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fchoose_005fexpr) >>>>> >>>>> "Note: This construct is only available for C. Furthermore, the unused >>>>> expression (exp1 or exp2 depending on the value of const_exp) may still >>>>> generate syntax errors. This may change in future revisions.” >>>>> >>>>> So, due to this limitation, when there is no counted_by attribute, the >>>>> __builtin_get_counted_by() still is evaluated by the compiler and errors >>>>> is issued and the compilation stops, this can be show from the small >>>>> testing case: >>>>> >>>>> [opc@qinzhao-ol8u3-x86 gcc]$ cat ttt.c >>>>> >>>>> struct flex { >>>>> unsigned int b; >>>>> int c[]; >>>>> } *array_flex; >>>>> >>>>> #define MY_ALLOC(P, FAM, COUNT) ({ \ >>>>> typeof(P) __p; \ >>>>> unsigned int __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \ >>>>> __p = (typeof(P)) __builtin_malloc(__size); \ >>>>> __builtin_choose_expr( \ >>>>> __builtin_has_attribute (__p->FAM, counted_by), \ >>>>> __builtin_counted_by_ref(__p->FAM) = COUNT, 0); \ >>>>> P = __p; \ >>>>> }) >>>>> >>>>> int main(int argc, char *argv[]) >>>>> { >>>>> MY_ALLOC(array_flex, c, 20); >>>>> return 0; >>>>> } >>>>> [opc@qinzhao-ol8u3-x86 gcc]$ sh t >>>>> ttt.c: In function ‘main’: >>>>> ttt.c:13:5: error: the argument must have ‘counted_by’ attribute >>>>> ‘__builtin_counted_by_ref’ >>>>> ttt.c:19:3: note: in expansion of macro ‘MY_ALLOC’ >>>>> >>>>> I checked the FE code on handling “__buiiltin_choose_expr”, Yes, it does >>>>> parse the __builtin_counted_by_ref(__p->FAM) even when >>>>> __builtin_has_attribute(__p->FAM, counted_by) is FALSE, and issued the >>>>> error when parsing __builtin_counted_by_ref and stopped the compilation. >>>>> >>>>> So, in order to support this approach, we first must fix the issue in the >>>>> current __builtin_choose_expr in GCC. Otherwise, it’s impossible for the >>>>> user to use this new builtin. >>>>> >>>>> Let me know your comments and suggestions. >>>>> >>>> Do you need to emit a diagnostic if the FAM doesn't have the >>>> counted_by attribute? It was originally supposed to "silently fail" if >>>> it didn't. We may need to do the same for Clang if so. >>> >>> Yes, “silently fail” should workaround this problem if fixing the issue in >>> the current __builtin_choose_expr is too complicate. >>> >>> I will study a little bit on how to fix the issue in __builtin_choose_expr >>> first. >>> >>> Martin and Joseph, any comment or suggestion from you? >> >> My recommendation would be not to change __builtin_choose_expr. >> >> The design where __builtin_get_counted_by returns a null >> pointer constant (void*)0 seems good. Most users will >> get an error which I think is what we want and for those >> that want it to work even if the attribute is not there, the >> following code seems perfectly acceptable to me: >> >> auto p = __builtin_get_counted_by(__p->FAM) >> *_Generic(p, void*: &(int){}, default: p) = 1; >> >> >> Kees also seemed happy with it. And if I understood it correctly, >> also Clang's bounds checking people can work with this. >> > The problem with this is explained in the Clang RFC [1]. Apple's team > rejects taking the address of the 'counter' field when using > -fbounds-safety. They suggested this as an alternative: > > __builtin_bounds_attr_arg(ptr->FAM) = COUNT; > > The __builtin_bounds_attr_arg(ptr->FAM) is replaced by an L-value to > the 'ptr->count' field during SEMA, and life goes on as normal. There > are a few reasons for this: > > 1. They want to track the relationship between the FAM and the > counter so that one isn't modified without the other being modified. > Allowing the address to be taken makes that check vastly harder. > > 2. Apple's implementation supports expressions in the '__counted_by' > attribute, thus the 'count' may be an R-value that can't have its > address taken. > > [1] > https://discourse.llvm.org/t/rfc-introducing-new-clang-builtin-builtin-get-counted-by/80836/ > > -bw