Am Montag, dem 15.07.2024 um 13:05 -0700 schrieb Kees Cook: > On Mon, Jul 15, 2024 at 07:20:31PM +0200, Martin Uecker wrote: > > No, there are still two many missing pieces. The following > > works already > > > > int h(int n, int buf[n]) > > { > > return __builtin_dynamic_object_size(buf, 1); > > } > > Yeah, this is nice. > > There are some interesting things happening around this general > idea. Clang has the rather limited attributes "pass_object_size" and > "pass_dynamic_object_size" that will work on function prototypes that > will inform a _bos or _bdos internally, but you can only choose _one_ > type to apply to a given function parameter: > > size_t h(char * const __attribute__((pass_dynamic_object_size(1))) buf) > { > return __builtin_dynamic_object_size(buf, 1); > } > > https://clang.llvm.org/docs/AttributeReference.html#pass-object-size-pass-dynamic-object-size > > I have found it easier to just make wrapper macros, as that can allow > both size types: > > size_t h(char *buf, const size_t p_max, const size_t p_min); > > #define h(p) \ > ({ \ > const size_t __p_max = __builtin_dynamic_object_size(p, 0); \ > const size_t __p_min = __builtin_dynamic_object_size(p, 1); \ > __h(p, __p_max, __p_min); \ > }) > > > But best is that it just gets handled automatically, which will be the > goals of the more generalized "counted_by" (and "sized_by") attributes > that will provide similar coverage as your example: > > size_t h(int * __attribute__((sized_by(bytes))) buf, int bytes) > { > return __builtin_dynamic_object_size(buf, 1); > } > > https://discourse.llvm.org/t/rfc-enforcing-bounds-safety-in-c-fbounds-safety/
Indeed, I already complained a lot to them about that design ;-) > > Those attributes end up being similar to what you have Well, the syntax is from C99, we just have to make it work. > only the explicit > predeclaration isn't needed. i.e. to put "int n" in your example after > "buf", it needs predeclaration: > > int h(int n; int buf[n], int n) > { > ... > } > > (But Clang doesn't appear to support predeclarations.) And isn't this a lot nicer? It also follows the exact same scoping rules of the language as everything else. In GCC the example above works also with this: int h(int n; char buf[n], int n) { return __builtin_dynamic_object_size(buf, 1); } https://godbolt.org/z/vfqoKaq7e and one can hide it with a macro if necessary I hope we will get the syntax with C2Y and also: struct { int n; char buf[.n]; }; In any case, I hope we get proper language integration and not a soup of attributes (although the attributes are a step up from not having bounds checking at all.). The problem in GCC is that the code for the access attributes that are internally used also for parameters with variably modified types is rather complicated and fragile, which makes it harder than necessary to add the missing pieces. I will probably try to simply add the .ACCESS_WITH_SIZE builtin in the FE to function parameters just like for 'counted_by'. Maybe this is already sufficient to make it work. In general I have the vague idea that at any point where an array decays or is adjusted into a pointer and size is then lost from the type, we could insert this builtin to make the size discoverable by BDOS later. A seamless handover from types to BDOS magic... Martin >