https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99630
Bug ID: 99630 Summary: missing -Warray-bounds accessing a trailing array of a virtual base class Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: msebor at gcc dot gnu.org Target Milestone: --- GCC issues -Warray-bounds for the out of bounds access to an object with an ordinary base class in f() but not for the same out of bounds access to an object with a virtual base class in g(). Both access should be diagnosed. The problem is that trailing_array() calls array_at_struct_end_p() which returns true for trailing array members without considering the type of the enclosing object. $ cat u.C && gcc -O2 -S -Wall -fdump-tree-vrp1=/dev/stdout u.C struct A1 { virtual ~A1 (); int a1a[1]; }; struct A2 { virtual ~A2 (); int a2a[1]; }; struct B1: A1 { }; struct B2: A2 { }; struct D1: B1, B2 { }; void f (D1 *p) { extern D1 d1; p->a1a[0] = (char*)d1.a1a - (char*)&d1; p->a1a[1] = (char*)d1.a2a - (char*)&d1; // -Warray-bounds (good) } struct V1: virtual A1 { }; struct V2: virtual A2 { }; struct D2: V1, V2 { }; void f (D2 *p) { extern D2 d2; p->a1a[0] = (char*)d2.a1a - (char*)&d2; p->a1a[1] = (char*)d2.a2a - (char*)&d2; // missing -Warray-bounds } ;; Function f (_Z1fP2D1, funcdef_no=0, decl_uid=2468, cgraph_uid=1, symbol_order=0) ;; 1 loops found ;; ;; Loop 0 ;; header 0, latch 1 ;; depth 0, outer -1 ;; nodes: 0 1 2 ;; 2 succs { 1 } SSA replacement table N_i -> { O_1 ... O_j } means that N_i replaces O_1, ..., O_j p_5 -> { p_2(D) } Incremental SSA update started at block: 2 Number of blocks in CFG: 3 Number of blocks to update: 1 ( 33%) Value ranges after VRP: p_2(D): struct D1 * VARYING p_5: struct D1 * [1B, +INF] EQUIVALENCES: { p_2(D) } (1 elements) u.C: In function ‘void f(D1*)’: u.C:21:11: warning: array subscript 1 is above array bounds of ‘int [1]’ [-Warray-bounds] 21 | p->a1a[1] = (char*)d1.a2a - (char*)&d1; // -Warray-bounds (good) | ~~~~~~~~^ u.C:4:7: note: while referencing ‘A1::a1a’ 4 | int a1a[1]; | ^~~ void f (struct D1 * p) { <bb 2> [local count: 1073741824]: p_2(D)->D.2450.D.2409.a1a[0] = 8; p_2(D)->D.2450.D.2409.a1a[1] = 24; return; } ;; Function f (_Z1fP2D2, funcdef_no=1, decl_uid=2566, cgraph_uid=2, symbol_order=1) ;; 1 loops found ;; ;; Loop 0 ;; header 0, latch 1 ;; depth 0, outer -1 ;; nodes: 0 1 2 ;; 2 succs { 1 } SSA replacement table N_i -> { O_1 ... O_j } means that N_i replaces O_1, ..., O_j _9 -> { _4 } p_10 -> { p_6(D) } Incremental SSA update started at block: 2 Number of blocks in CFG: 3 Number of blocks to update: 1 ( 33%) Value ranges after VRP: _1: int (*) () * VARYING _2: long int VARYING _3: sizetype VARYING _4: struct D2 * [1B, +INF] p_6(D): struct D2 * VARYING _9: struct D2 * [1B, +INF] EQUIVALENCES: { _4 } (1 elements) p_10: struct D2 * [1B, +INF] EQUIVALENCES: { p_6(D) } (1 elements) void f (struct D2 * p) { int (*) () * _1; long int _2; sizetype _3; struct D2 * _4; <bb 2> [local count: 1073741824]: _1 = p_6(D)->D.2549._vptr.V1; _2 = MEM[(long int *)_1 + -24B]; _3 = (sizetype) _2; _4 = p_6(D) + _3; MEM[(struct A1 *)_4].a1a[0] = 24; MEM[(struct A1 *)_4].a1a[1] = 40; <<< _4's type is D2 and a1a[1] overlaps its _vptr return; }