/* PR middle-end/91647 - missing -Warray-bounds accessing a zero-length array of a declared object { dg-do "compile" } { dg-options "-O2 -Wall" } */ typedef __INT16_TYPE__ int16_t; typedef __INT32_TYPE__ int32_t; void sink (void*); /* Exercise a true flexible member. */ struct AX { int32_t n; int16_t ax[]; // { dg-message "while referencing 'ax'" "member" } }; static void warn_ax_local (struct AX *p) { p->ax[0] = 0; // { dg-warning "\\\[-Warray-bounds" } p->ax[1] = 1; // { dg-warning "\\\[-Warray-bounds" } } static void nowarn_ax_extern (struct AX *p) { p->ax[0] = 0; p->ax[99] = 99; p->ax[999] = 999; p->ax[9999] = 9999; } static void warn_ax_local_buf (struct AX *p) { p->ax[0] = 4; p->ax[1] = 5; p->ax[2] = 6; // { dg-warning "\\\[-Warray-bounds" } p->ax[3] = 7; // { dg-warning "\\\[-Warray-bounds" } p->ax[4] = 8; // { dg-warning "\\\[-Warray-bounds" } } static void warn_ax_extern_buf (struct AX *p) { p->ax[0] = 9; p->ax[1] = 10; p->ax[2] = 11; p->ax[3] = 12; // { dg-warning "\\\[-Warray-bounds" } p->ax[4] = 13; // { dg-warning "\\\[-Warray-bounds" } p->ax[5] = 14; // { dg-warning "\\\[-Warray-bounds" } } static void nowarn_ax_extern_bufx (struct AX *p) { p->ax[0] = 0; p->ax[99] = 99; p->ax[999] = 999; p->ax[9999] = 9999; } static void nowarn_ax_ref (struct AX *p) { p->ax[0] = 0; p->ax[99] = 99; p->ax[999] = 999; p->ax[9999] = 9999; } void test_ax (struct AX *p, unsigned n) { { struct AX sax; // { dg-message "defined here" "struct definition" } warn_ax_local (&sax); sink (&sax); } { extern struct AX xsax; nowarn_ax_extern (&xsax); sink (&xsax); } { /* Verify out-of-bounds access to the local BUF is diagnosed. */ char ax_buf_p2[sizeof (struct AX) + 2 * sizeof (int16_t)]; warn_ax_local_buf ((struct AX*) ax_buf_p2); sink (ax_buf_p2); } { /* Verify out-of-bounds access to the extern BUF with a known bound is diagnosed. */ extern char ax_buf_p3[sizeof (struct AX) + 3 * sizeof (int16_t)]; warn_ax_extern_buf ((struct AX*) ax_buf_p3); sink (ax_buf_p3); } { /* Verify that accesses to BUFX with an unknown bound are not diagnosed. */ extern char bufx[]; nowarn_ax_extern_bufx ((struct AX*) bufx); sink (bufx); } { /* Verify that accesses to BUFN with a runtime bound are not diagnosed. */ char bufn[n]; nowarn_ax_extern_bufx ((struct AX*) bufn); sink (bufn); } nowarn_ax_ref (p); } /* Exercise a zero-length trailing member array. It's the same as above except that extern declarations with no definitions are considered to have zero elements (they can't be initialized to have any). */ struct A0 { int32_t n; int16_t a0[0]; // { dg-message "while referencing 'a0'" "member" } }; static void warn_a0_local (struct A0 *p) { p->a0[0] = 0; // { dg-warning "\\\[-Warray-bounds" } p->a0[1] = 1; // { dg-warning "\\\[-Warray-bounds" } } static void warn_a0_extern (struct A0 *p) { p->a0[0] = 2; // { dg-warning "\\\[-Warray-bounds" } p->a0[1] = 3; // { dg-warning "\\\[-Warray-bounds" } } static void warn_a0_local_buf (struct A0 *p) { p->a0[0] = 4; p->a0[1] = 5; p->a0[2] = 6; // { dg-warning "\\\[-Warray-bounds" } p->a0[3] = 7; // { dg-warning "\\\[-Warray-bounds" } p->a0[4] = 8; // { dg-warning "\\\[-Warray-bounds" } } static void warn_a0_extern_buf (struct A0 *p) { p->a0[0] = 9; p->a0[1] = 10; p->a0[2] = 11; p->a0[3] = 12; // { dg-warning "\\\[-Warray-bounds" } p->a0[4] = 13; // { dg-warning "\\\[-Warray-bounds" } p->a0[5] = 14; // { dg-warning "\\\[-Warray-bounds" } } static void nowarn_a0_extern_bufx (struct A0 *p) { p->a0[0] = 0; p->a0[99] = 99; p->a0[999] = 999; p->a0[9999] = 9999; } static void nowarn_a0_ref (struct A0 *p) { p->a0[0] = 0; p->a0[99] = 99; p->a0[999] = 999; p->a0[9999] = 9999; } void test_a0 (struct A0 *p, unsigned n) { { struct A0 sa0; // { dg-message "defined here" "struct definition" } warn_a0_local (&sa0); sink (&sa0); } { extern struct A0 xsa0; // { dg-message "defined here" "struct definition" } warn_a0_extern (&xsa0); sink (&xsa0); } { /* Verify out-of-bounds access to the local BUF is diagnosed. */ char a0_buf_p2[sizeof (struct A0) + 2 * sizeof (int16_t)]; warn_a0_local_buf ((struct A0*) a0_buf_p2); sink (a0_buf_p2); } { /* Verify out-of-bounds access to the extern BUF with a known bound is diagnosed. */ extern char a0_buf_p3[sizeof (struct A0) + 3 * sizeof (int16_t)]; warn_a0_extern_buf ((struct A0*) a0_buf_p3); sink (a0_buf_p3); } { /* Verify that accesses to BUFX with an unknown bound are not diagnosed. */ extern char bufx[]; nowarn_a0_extern_bufx ((struct A0*) bufx); sink (bufx); } { /* Verify that accesses to BUFN with a runtime bound are not diagnosed. */ char bufn[n]; nowarn_a0_extern_bufx ((struct A0*) bufn); sink (bufn); } nowarn_a0_ref (p); } /* Exercise a one-element trailing member array. It's the same as above except that it has exactly one element. */ struct A1 { int32_t n; int16_t a1[1]; // { dg-message "while referencing 'a1'" } }; static void warn_a1_local_noinit (struct A1 *p) { p->a1[0] = 0; p->a1[1] = 1; // { dg-warning "\\\[-Warray-bounds" } p->a1[2] = 2; // { dg-warning "\\\[-Warray-bounds" } } static void warn_a1_extern (struct A1 *p) { p->a1[0] = 0; p->a1[1] = 1; // { dg-warning "\\\[-Warray-bounds" } p->a1[2] = 2; // { dg-warning "\\\[-Warray-bounds" } } static void warn_a1_init (struct A1 *p) { p->a1[0] = 0; p->a1[1] = 1; // { dg-warning "\\\[-Warray-bounds" } p->a1[2] = 2; // { dg-warning "\\\[-Warray-bounds" } } static void warn_a1_local_buf (struct A1 *p) { p->a1[0] = 0; p->a1[1] = 1; p->a1[2] = 2; p->a1[3] = 3; p->a1[4] = 4; // { dg-warning "\\\[-Warray-bounds" } } static void warn_a1_extern_buf (struct A1 *p) { p->a1[0] = 0; p->a1[1] = 1; p->a1[2] = 2; p->a1[3] = 3; p->a1[4] = 4; p->a1[5] = 5; // { dg-warning "\\\[-Warray-bounds" } } static void nowarn_a1_extern_bufx (struct A1 *p) { p->a1[0] = 0; p->a1[99] = 99; p->a1[999] = 999; p->a1[9999] = 9999; } static void nowarn_a1_ref (struct A1 *p) { p->a1[0] = 0; p->a1[99] = 99; p->a1[999] = 999; p->a1[9999] = 9999; } void test_a1 (struct A1 *p, unsigned n) { { struct A1 a1; warn_a1_local_noinit (&a1); sink (&a1); } { extern struct A1 a1x; warn_a1_extern (&a1x); sink (&a1x); } { struct A1 a1 = { 0, { 1 } }; warn_a1_init (&a1); sink (&a1); } { /* Verify out-of-bounds access to the local BUF is diagnosed. */ char buf_p2[sizeof (struct A1) + 2 * sizeof (int16_t)]; warn_a1_local_buf ((struct A1*) buf_p2); sink (buf_p2); } { /* Verify out-of-bounds access to the extern BUF with a known bound is diagnosed. */ extern char a1_buf_p3[sizeof (struct A1) + 3 * sizeof (int16_t)]; warn_a1_extern_buf ((struct A1*) a1_buf_p3); sink (a1_buf_p3); } { /* Verify that accesses to BUFX with an unknown bound are not diagnosed. */ extern char bufx[]; nowarn_a1_extern_bufx ((struct A1*) bufx); sink (bufx); } { /* Verify that accesses to BUFN with a runtime bound are not diagnosed. */ char bufn[n]; nowarn_a1_extern_bufx ((struct A1*) bufn); sink (bufn); } nowarn_a1_ref (p); } /* Exercise a two-element trailing member array. It's treated the same as an interior array member. */ struct A2 { int32_t n; int16_t a2[2]; // { dg-message "while referencing 'a2'" } }; static void warn_a2_noinit (struct A2 *p) { p->a2[0] = 0; p->a2[1] = 1; p->a2[2] = 2; // { dg-warning "\\\[-Warray-bounds" } } static void warn_a2_init (struct A2 *p) { p->a2[0] = 0; p->a2[1] = 1; p->a2[2] = 2; // { dg-warning "\\\[-Warray-bounds" } p->a2[9] = 9; // { dg-warning "\\\[-Warray-bounds" } } static void warn_a2_ref (struct A2 *p) { p->a2[0] = 0; p->a2[1] = 1; p->a2[2] = 2; // { dg-warning "\\\[-Warray-bounds" } p->a2[9] = 9; // { dg-warning "\\\[-Warray-bounds" } } void test_a2 (struct A2 *p) { { struct A2 a2; warn_a2_noinit (&a2); sink (&a2); } { struct A2 a2 = { 0, { 1, 2 } }; warn_a2_init (&a2); sink (&a2); } warn_a2_ref (p); }