https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128274
Bug ID: 128274
Summary: [16/17 Regression] &p->payload on counted_by FAM omits
.ACCESS_WITH_SIZE in build_unary_op
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: 220245569 at seu dot edu.cn
CC: 220255623 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
Target Milestone: ---
Target: *-*-*
Summary
-------
In GCC 16/17, taking the address of a flexible array member annotated with
`__attribute__((counted_by(count)))` via `&p->payload` omits the
`.ACCESS_WITH_SIZE` wrapper, causing
`__builtin_dynamic_object_size(&p->payload, 0)`
to return `-1` (unknown) and `_FORTIFY_SOURCE=3` `__memcpy_chk` to fold to an
unchecked `memcpy`.
When GCC 16 refactored `.ACCESS_WITH_SIZE` generation out of
`build_component_ref`
into callers (`c_decay_conversion` for array-to-pointer decay `p->payload`), it
missed the `ADDR_EXPR` case in `build_unary_op`
(`gcc/c/c-typeck.cc:6219-6339`).
As a result, while `p->payload` emits `.ACCESS_WITH_SIZE` and evaluates
`__builtin_dynamic_object_size` to `p->count`, `&p->payload` emits a raw
`ADDR_EXPR <COMPONENT_REF>` and loses its dynamic bound.
Reproducer
----------
$ cat trigger.c
#include <stddef.h>
struct packet {
size_t count;
char payload[] __attribute__((counted_by(count)));
};
size_t bdos_decay(struct packet *p) {
return __builtin_dynamic_object_size(p->payload, 0);
}
size_t bdos_addr(struct packet *p) {
return __builtin_dynamic_object_size(&p->payload, 0);
}
void copy_addr(struct packet *p, const void *src, size_t len) {
__builtin___memcpy_chk(
&p->payload, src, len, __builtin_dynamic_object_size(&p->payload, 0));
}
Compile flag: gcc -O2 -S trigger.c
$ cat trigger.s
bdos_decay:
movq (%rdi), %rax # returns p->count
ret
bdos_addr:
movq $-1, %rax # BUG: returns -1 (unknown)!
ret
copy_addr:
addq $8, %rdi
jmp memcpy # BUG: __memcpy_chk folded to unchecked
memcpy!
Suggested Fix
-------------
In `build_unary_op` (`gcc/c/c-typeck.cc:6335`, `case ADDR_EXPR:`), call
`c_build_fun_call_access_with_size` when the operand is a `COMPONENT_REF`
referencing a `counted_by` flexible array member.