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.

> (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.


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


-Kees

-- 
Kees Cook

Reply via email to