> On Jan 30, 2024, at 12:41 AM, Kees Cook <keesc...@chromium.org> wrote: > > On Mon, Jan 29, 2024 at 10:45:23PM +0000, Qing Zhao wrote: >> There are two things here. >> >> 1. The value of the “counted-by” is 0; (which is easy to be understood) >> 2. The result of the _builtin_object_size when see a “counted-by” 0. >> >> For 1, it’s simple, if we see a counted-by value <= 0, then counted-by is 0; > > Okay, that's good; this matches my understanding. :) > >> But for 2, when the _builtin_object_size sees a “counted-by” 0, what’s value >> it will return for the object size? >> >> Can we return 0 for the object size? > > I don't see why not. For example: > > // -O2 -fstrict-flex-arrays=3 > struct s { > int a; > int b[4]; > } foo; > > #define report(x) printf("%s: %zu\n", #x, (size_t)(x)) > > int main(int argc, char *argv[]) > { > struct s foo; > report(__builtin_dynamic_object_size(&foo.b[4], 0)); > report(__builtin_dynamic_object_size(&foo.b[5], 0)); > report(__builtin_dynamic_object_size(&foo.b[-10], 0)); > report(__builtin_dynamic_object_size(&foo.b[4], 1)); > report(__builtin_dynamic_object_size(&foo.b[5], 1)); > report(__builtin_dynamic_object_size(&foo.b[-10], 1)); > report(__builtin_dynamic_object_size(&foo.b[4], 2)); > report(__builtin_dynamic_object_size(&foo.b[5], 2)); > report(__builtin_dynamic_object_size(&foo.b[-10], 2)); > report(__builtin_dynamic_object_size(&foo.b[4], 3)); > report(__builtin_dynamic_object_size(&foo.b[5], 3)); > report(__builtin_dynamic_object_size(&foo.b[-10], 3)); > return 0; > } > > shows: > > __builtin_dynamic_object_size(&foo.b[4], 0): 0 > __builtin_dynamic_object_size(&foo.b[5], 0): 0 > __builtin_dynamic_object_size(&foo.b[-10], 0): 0 > __builtin_dynamic_object_size(&foo.b[4], 1): 0 > __builtin_dynamic_object_size(&foo.b[5], 1): 0 > __builtin_dynamic_object_size(&foo.b[-10], 1): 0 > __builtin_dynamic_object_size(&foo.b[4], 2): 0 > __builtin_dynamic_object_size(&foo.b[5], 2): 0 > __builtin_dynamic_object_size(&foo.b[-10], 2): 0 > __builtin_dynamic_object_size(&foo.b[4], 3): 0 > __builtin_dynamic_object_size(&foo.b[5], 3): 0 > __builtin_dynamic_object_size(&foo.b[-10], 3): 0 > > This is showing "no bytes left" for the end of the b array, and if this > index keeps going, it still reports 0 if we're past the end of the object > completely. And it is similarly capped for negative indexes. This is > true for all the __bos type bits. > > A "counted-by" of 0 (or below) would have the same meaning as an out of > bounds index here.
Okay. I will keep this behavior when counted-by is zero (and negative) for __bos. > >> (As I mentioned in the previous email, 0 in __builtin_object_size doesn’t >> mean size 0, >> it means UNKNOWN_SIZE when the type is 2/3, So, what’s value we should >> return for the size 0?) >> https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html > > I think I see what you mean, but I still think it should be 0 for 2/3, > regardless of the documented interpretation. If that's the current > response for a pathological index under 2/3, then I think it's totally > reasonable that it should do the same for pathological bounds. Okay, will keep this behavior for “counted-by” zero. (But still feel that 0 for 2/3, i.e the MINIMUM size will represent as UNKNOWN_SIZE. If that’s the value kernel expected, that’s good) > > > And BTW, it seems there are 0-sized objects, though maybe they're some > kind of special case: > > struct s { > int a; > struct { } nothing; > int b; > }; > > #define report(x) printf("%s: %zu\n", #x, (size_t)(x)) > > int main(int argc, char *argv[]) > { > struct s foo; > report(__builtin_dynamic_object_size(&foo.nothing, 1)); > } > > shows: > > __builtin_dynamic_object_size(&foo.nothing, 1): 0 Looks like that GCC has such extension: https://gcc.gnu.org/onlinedocs/gcc/Empty-Structures.html ***GCC permits a C structure to have no members: struct empty { }; The structure has size zero. In C++, empty structures are part of the language. G++ treats empty structures as if they had a single member of type char. Thanks. Qing > > -Kees > > -- > Kees Cook