bwendling wrote:

> We've discussed this before, years ago. Previously, the sticking point was: 
> how is LLVM going to know what the frontend considers the closest surrounding 
> subobject to be? The LLVM type doesn't give you that information, and it 
> seems like there's nowhere else that LLVM can get it from either, so this 
> flag ends up not being useful and the best we can do is to give a 
> conservatively-correct answer -- the complete object size if we want an upper 
> bound, or 0 if we want a lower bound.

Right now we're giving a wrong answer (see below), so that's no good. If we're 
going to err on the side of caution, then we should return the default "can't 
calculate the size" value.

When you say that we can't detect what the front-end considers the "closest 
surrounding subobject" to be, is that mostly due to corner cases or is it a 
more general concern? (Note, we're really only interested in supporting this 
for C structs. C++ structs / classes would require therapy.)

> Clang does respect the "subobject" flag if it can symbolically evaluate the 
> operand of `__builtin_object_size` sufficiently to determine which subobject 
> is being referenced. Previously we've thought that that was the best we could 
> do.

This is why the current behavior is wrong, in my opinion. The motivating 
example is below:

```
struct suspend_stats {
        int     success;
        int     fail;
        int     failed_freeze;
        int     failed_prepare;
        int     failed_suspend;
        int     failed_suspend_late;
        int     failed_suspend_noirq;
        int     failed_resume;
        int     failed_resume_early;
        int     failed_resume_noirq;
#define REC_FAILED_NUM  2
        int     last_failed_dev;
        char    failed_devs[REC_FAILED_NUM][40]; /* offsetof(struct 
suspend_stats, failed_devs) == 44 */
        int     last_failed_errno;
        int     bar;
};

#define report(x) __builtin_printf(#x ": %zu\n", x)

int main(int argc, char *argv[])
{
    struct suspend_stats foo;

    report(sizeof(foo.failed_devs[1]));
    report(sizeof(foo.failed_devs[argc]));
    report(__builtin_dynamic_object_size(&foo.fail, 0));
    report(__builtin_dynamic_object_size(&foo.fail, 1));
    report(__builtin_dynamic_object_size(&foo.failed_freeze, 0));
    report(__builtin_dynamic_object_size(foo.failed_devs[1], 0));
    report(__builtin_dynamic_object_size(foo.failed_devs[1], 1));
    report(__builtin_dynamic_object_size(foo.failed_devs[argc], 0));
    report(__builtin_dynamic_object_size(foo.failed_devs[argc], 1));

    return 0;
}
```

The output with this change is now:

```
__builtin_dynamic_object_size(&foo.fail, 0): 128
__builtin_dynamic_object_size(&foo.fail, 1): 4
__builtin_dynamic_object_size(&foo.failed_freeze, 0): 124
__builtin_dynamic_object_size(foo.failed_devs[1], 0): 48
__builtin_dynamic_object_size(foo.failed_devs[1], 1): 40
__builtin_dynamic_object_size(foo.failed_devs[argc], 0): 48
__builtin_dynamic_object_size(foo.failed_devs[argc], 1): 40
```

Without the change, the last line is:

```
__builtin_dynamic_object_size(foo.failed_devs[argc], 1): 48
```

Which isn't correct according to GNU's documentation. So if we can't honor the 
TYPE bit, then we should return `-1 / 0` here, right?

https://github.com/llvm/llvm-project/pull/78526
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to