More thoughts on the following example Kees provided: > On Jul 17, 2023, at 7:40 PM, Kees Cook <keesc...@chromium.org> wrote: >> >> The counted_by attribute is used to annotate a Flexible array member on how >> many elements it will have. >> However, if this information can not accurately reflect the real number of >> elements for the array allocated, >> What’s the purpose of such information? > > For example, imagine code that allocates space for 100 elements since > the common case is that the number of elements will grow over time. > Elements are added as it goes. For example: > > struct grows { > int alloc_count; > int valid_count; > struct element item[] __counted_by(valid_count); > } *p; > > void something(void) > { > p = malloc(sizeof(*p) + sizeof(*p->item) * 100); > p->alloc_count = 100; > p->valid_count = 0; > > /* this loop doesn't check that we don't go over 100. */ > while (items_to_copy) { > struct element *item_ptr = get_next_item(); > /* __counted_by stays in sync: */ > p->valid_count++; > p->item[p->valid_count - 1] = *item_ptr; > } > } > > We would want to catch cases there p->item[] is accessed with an index > that is >= p->valid_count, even though the allocation is (currently) > larger. > > However, if we ever reached valid_count >= alloc_count, we need to trap > too, since we can still "see" the true allocation size. > > Now, the __alloc_size hint is visible in very few places, so if there is > a strong reason to do so, I can live with saying that __counted_by takes > full precedence over __alloc_size. It seems it should be possible to > compare when both are present, but I can live with __counted_by being > the universal truth. :)
In the above use case (not sure how popular such user case is?), the major questions are: for one object with flexible array member, 1. Shall we allow the situation when the allocated size for the object and the number of element for the contained FAM are mismatched? If the answer to 1 is YES (to support such user cases), then 2. If there is a mismatch between these two, should the number of element impact the allocated size for the object? (__builtin_object_size()) From the doc of object size checking: (https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html) ===== Built-in Function: size_t __builtin_object_size (const void * ptr, int type) is a built-in construct that returns a constant number of bytes from ptr to the end of the object ptr pointer points to (if known at compile time). To determine the sizes of dynamically allocated objects the function relies on the allocation functions called to obtain the storage to be declared with the alloc_size attribute (see Common Function Attributes). __builtin_object_size never evaluates its arguments for side effects. If there are any side effects in them, it returns (size_t) -1 for type 0 or 1 and (size_t) 0 for type 2 or 3. If there are multiple objects ptr can point to and all of them are known at compile time, the returned number is the maximum of remaining byte counts in those objects if type & 2 is 0 and minimum if nonzero. If it is not possible to determine which objects ptr points to at compile time, __builtin_object_size should return (size_t) -1 for type 0 or 1 and (size_t) 0 for type 2 or 3. ===== Based on the current documentation for __bos, I think that the answer should be NO, i.e, we should not use the counted_by info to change the REAL allocated size for the object. 3. Then, As pointed out also by Martin, only the bounds check (including -Warray-bounds or -fsanitizer=bounds) should be impacted by the counted_by information, since these checks are based on the TYPE system, and “counted_by” info should be treated as a complement to the TYPE system. Let me know your opinions. Qing