Bug 114713 - incorrect TBAA for struct with flexible array member or GNU zero size
Summary: incorrect TBAA for struct with flexible array member or GNU zero size
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 14.0
: P3 normal
Target Milestone: ---
Assignee: uecker
URL:
Keywords: alias, lto, wrong-code
Depends on:
Blocks:
 
Reported: 2024-04-14 15:34 UTC by Martin Uecker
Modified: 2025-04-14 21:59 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work: 15.0
Known to fail: 14.2.0, 5.1.0
Last reconfirmed: 2024-10-27 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Uecker 2024-04-14 15:34:29 UTC
If one mixes a struct with FAM and one with zero size at the end, then TBAA considers them incompatible for aliasing purposes when using LTO. One could decide that those are incompatible types, but this would break code that mixes both, e.g. during a transition time to standard FAMs. Also affects old versions of GCC.

https://godbolt.org/z/xodMK9sqE


struct foo { int x; char a[]; };

void test_bar(void* b);

__attribute__((noinline))
int test_foo(struct foo* a, void* b)
{
        a->x = 1;
        test_bar(b);
        return a->x;
}

int main()
{
        struct foo y;

        if (2 != test_foo(&y, &y))
                __builtin_abort();

        return 0;
}

// TU2
struct foo { int x; char a[0]; };

void test_bar(void* b)
{
        struct foo *p = b;
        p->x = 2;
}
Comment 1 Richard Biener 2024-04-15 08:26:20 UTC
[] and [0] are not the same.  Note the C and C++ frontends encode [0] (or did encode) differently.

See tree.cc:gimple_canonical_types_compatible_p

I agree that from a QOI perspective [] and [0] should be compatible.

Note [0] can have many "equivalent" domains, [3:2], [0:-1], [1:0], etc.
but the current code has

      /* Array types are the same if the element types are the same and
         the number of elements are the same.  */
...
              /* The minimum/maximum values have to be the same.  */
              if ((min1 == min2
                   || (min1 && min2

which is somewhat contradicting comments.

See also layout_type which says, when computing TYPE_SIZE of an array:

            /* ??? We have no way to distinguish a null-sized array from an
               array spanning the whole sizetype range, so we arbitrarily
               decide that [0, -1] is the only valid representation.  */
            if (integer_zerop (length)
                && TREE_OVERFLOW (length)
                && integer_zerop (lb))
              length = size_zero_node;

revealing that the constraints on TYPE_DOMAIN are not very well specified.
Comment 2 Richard Biener 2024-04-15 08:32:41 UTC
Also note that people might find it reasonable to access

struct { int n; int a[4]; } a = { 4, };

via

struct X { int n; int a[] } *p;

The fortran frontend goes some lengths to make this work for array
descriptors statically allocated by accessing the storage always
via the type with the flexible array member.  But that also relies
on GCC middle-end semantics, accessing an automatic variable with
a declared type via a not compatible type, thus changing its effective type.

The only valid C way is to resort to dynamic (stack) allocation.
Comment 3 GCC Commits 2024-12-12 12:27:41 UTC
The master branch has been updated by Martin Uecker <uecker@gcc.gnu.org>:

https://gcc.gnu.org/g:d46c7f313b5a30ee04080f249e31e12987d50aa2

commit r15-6170-gd46c7f313b5a30ee04080f249e31e12987d50aa2
Author: Martin Uecker <uecker@tugraz.at>
Date:   Sat Nov 23 08:04:05 2024 +0100

    Fix type compatibility for types with flexible array member 2/2 [PR113688,PR114713,PR117724]
    
    For checking or computing TYPE_CANONICAL, ignore the array size when it is
    the last element of a structure or union.  To not get errors because of
    an inconsistent number of members, zero-sized arrays which are the last
    element are not ignored anymore when checking the fields of a struct.
    
            PR c/113688
            PR c/114014
            PR c/114713
            PR c/117724
    
    gcc/ChangeLog:
            * tree.cc (gimple_canonical_types_compatible_p): Add exception.
    
    gcc/lto/ChangeLog:
            * lto-common.cc (hash_canonical_type): Add exception.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/pr113688.c: New test.
            * gcc.dg/pr114014.c: New test.
            * gcc.dg/pr114713.c: New test.
            * gcc.dg/pr117724.c: New test.
Comment 4 uecker 2024-12-12 14:46:46 UTC
Fixed on trunk.
Comment 5 GCC Commits 2025-03-30 09:58:32 UTC
The releases/gcc-14 branch has been updated by Martin Uecker <uecker@gcc.gnu.org>:

https://gcc.gnu.org/g:73549be0a3c819b2ab78e0e973f5b4d41b9f4a2d

commit r14-11478-g73549be0a3c819b2ab78e0e973f5b4d41b9f4a2d
Author: Martin Uecker <uecker@tugraz.at>
Date:   Sat Nov 23 08:04:05 2024 +0100

    Fix type compatibility for types with flexible array member 2/2 [PR113688,PR114713,PR117724]
    
    For checking or computing TYPE_CANONICAL, ignore the array size when it is
    the last element of a structure or union.  To not get errors because of
    an inconsistent number of members, zero-sized arrays which are the last
    element are not ignored anymore when checking the fields of a struct.
    
            PR c/113688
            PR c/114014
            PR c/114713
            PR c/117724
    
    gcc/ChangeLog:
            * tree.cc (gimple_canonical_types_compatible_p): Add exception.
    
    gcc/lto/ChangeLog:
            * lto-common.cc (hash_canonical_type): Add exception.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/pr113688.c: New test.
            * gcc.dg/pr114014.c: New test.
            * gcc.dg/pr114713.c: New test.
            * gcc.dg/pr117724.c: New test.
    
    (cherry picked from commit d46c7f313b5a30ee04080f249e31e12987d50aa2)
Comment 6 GCC Commits 2025-04-14 21:59:53 UTC
The releases/gcc-14 branch has been updated by Eric Botcazou <ebotcazou@gcc.gnu.org>:

https://gcc.gnu.org/g:5457388f58262bee41ae1d744ff6f3da34119e2d

commit r14-11611-g5457388f58262bee41ae1d744ff6f3da34119e2d
Author: Eric Botcazou <ebotcazou@adacore.com>
Date:   Mon Apr 14 23:35:43 2025 +0200

    Revert very recent backport of changes to the type system
    
    The backport of the change made for PR c/113688 onto the 14 branch a couple
    of weeks ago has seriously broken the LTO compiler for the Ada language on
    the 14 branch, because it changes the GCC type system for the sake of C in
    a way that is not compatible with simple discriminated types in Ada.  To be
    more precise, useless_type_conversion_p now returns true for some (view-)
    conversions that are needed by the rest of the compiler.
    
    gcc/
            PR lto/119792
            Revert
    
            Backported from master:
                2024-12-12  Martin Uecker  <uecker@tugraz.at>
    
            PR c/113688
            PR c/114014
            PR c/114713
            PR c/117724
            * tree.cc (gimple_canonical_types_compatible_p): Add exception.
            (verify_type): Add exception.
    
    gcc/lto/
            PR lto/119792
            Revert
    
            Backported from master:
                2024-12-12  Martin Uecker  <uecker@tugraz.at>
            * lto-common.cc (hash_canonical_type): Add exception.
    
    gcc/testsuite/
            * gcc.dg/pr113688.c: Delete.
            * gcc.dg/pr114014.c: Likewise.
            * gcc.dg/pr114713.c: Likewise.
            * gcc.dg/pr117724.c: Likewise