https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123160
Bug ID: 123160
Summary: pointer_plus folding breaks objsz
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: amacleod at redhat dot com
Target Milestone: ---
Target: x86_64-pc-linux-gnu
Created attachment 63066
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=63066&action=edit
testcase
The attached testcase demonstrates that gimple_fold of a pointer_plus
expression can result in a loss of information.
struct A
{
char a[10];
int b;
char c[10];
} a;
The passing function:
int
passes (void)
{
void *r;
r = &a.a[4];
r = memset (r, 'a', 2);
r = memset (r + 2, 'b', 2) + 2;
if (__builtin_object_size (r, 3) != sizeof (a.a) - 8)
__builtin_abort ();
}
obfuscates r enough that optimization doesn't do much, and the objsz pass can
walk the use def chains and figure out that the call to abort() can be
eliminated, resulting in
r_5 = memset (&a.a[4], 97, 2);
_1 = r_5 + 2;
memset (_1, 98, 2);
The fails () function simply removes the first memset. This allows the
expression &a.a[4] + 2 to be folded into a generic
&MEM <char> [(void *)&a + 6B]
which loses the information that it points to the a[10] object, and now refers
to the containing struct A.
This causes the objsz pass to use the size of the structure instead of the
array and the call to abort becomes always called. This results in:
<bb 2> [count: 0]:
memset (&MEM <char> [(void *)&a + 6B], 98, 2);
__builtin_abort ();
I believe this is due to the way gimple_fold_stmt_to_constant_1 handles the
POINTER_PLUS_EXPR case by simply generating the MEM.
This fails back to at least GCC 13