PR middle-end/98266 - bogus array subscript is partly outside array bounds on virtual inheritance
gcc/ChangeLog: PR middle-end/98266 * gimple-array-bounds.cc (inbounds_vbase_memaccess_p): New function. (array_bounds_checker::check_array_bounds): Call it. gcc/testsuite/ChangeLog: PR middle-end/98266 * g++.dg/warn/Warray-bounds-15.C: New test. * g++.dg/warn/Warray-bounds-18.C: New test. * g++.dg/warn/Warray-bounds-19.C: New test. * g++.dg/warn/Warray-bounds-20.C: New test. * g++.dg/warn/Warray-bounds-21.C: New test.
This commit is contained in:
parent
7f5ff78ff3
commit
f3daa6c0fd
|
@ -890,6 +890,50 @@ array_bounds_checker::check_addr_expr (location_t location, tree t)
|
|||
}
|
||||
}
|
||||
|
||||
/* Return true if T is a reference to a member of a base class that's within
|
||||
the bounds of the enclosing complete object. The function "hacks" around
|
||||
problems discussed in pr98266 and pr97595. */
|
||||
|
||||
static bool
|
||||
inbounds_vbase_memaccess_p (tree t)
|
||||
{
|
||||
if (TREE_CODE (t) != COMPONENT_REF)
|
||||
return false;
|
||||
|
||||
tree mref = TREE_OPERAND (t, 0);
|
||||
if (TREE_CODE (mref) != MEM_REF)
|
||||
return false;
|
||||
|
||||
/* Consider the access if its type is a derived class. */
|
||||
tree mreftype = TREE_TYPE (mref);
|
||||
if (!RECORD_OR_UNION_TYPE_P (mreftype)
|
||||
|| !TYPE_BINFO (mreftype))
|
||||
return false;
|
||||
|
||||
/* Compute the size of the referenced object (it could be dynamically
|
||||
allocated). */
|
||||
access_ref aref; // unused
|
||||
tree refop = TREE_OPERAND (mref, 0);
|
||||
tree refsize = compute_objsize (refop, 1, &aref);
|
||||
if (!refsize || TREE_CODE (refsize) != INTEGER_CST)
|
||||
return false;
|
||||
|
||||
/* Compute the byte offset of the member within its enclosing class. */
|
||||
tree fld = TREE_OPERAND (t, 1);
|
||||
tree fldpos = byte_position (fld);
|
||||
if (TREE_CODE (fldpos) != INTEGER_CST)
|
||||
return false;
|
||||
|
||||
/* Compute the byte offset of the member with the outermost complete
|
||||
object by adding its offset computed above to the MEM_REF offset. */
|
||||
tree refoff = TREE_OPERAND (mref, 1);
|
||||
tree fldoff = int_const_binop (PLUS_EXPR, fldpos, refoff);
|
||||
|
||||
/* Return true if the member offset is less than the size of the complete
|
||||
object. */
|
||||
return tree_int_cst_lt (fldoff, refsize);
|
||||
}
|
||||
|
||||
/* Callback for walk_tree to check a tree for out of bounds array
|
||||
accesses. The array_bounds_checker class is passed in DATA. */
|
||||
|
||||
|
@ -919,8 +963,14 @@ array_bounds_checker::check_array_bounds (tree *tp, int *walk_subtree,
|
|||
else if (TREE_CODE (t) == ADDR_EXPR)
|
||||
{
|
||||
checker->check_addr_expr (location, t);
|
||||
*walk_subtree = FALSE;
|
||||
*walk_subtree = false;
|
||||
}
|
||||
else if (inbounds_vbase_memaccess_p (t))
|
||||
/* Hack: Skip MEM_REF checks in accesses to a member of a base class
|
||||
at an offset that's within the bounds of the enclosing object.
|
||||
See pr98266 and pr97595. */
|
||||
*walk_subtree = false;
|
||||
|
||||
/* Propagate the no-warning bit to the outer expression. */
|
||||
if (warned)
|
||||
TREE_NO_WARNING (t) = true;
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* PR middle-end/98266 - bogus array subscript is partly outside array
|
||||
bounds on virtual inheritance
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
// This matters for the test case.
|
||||
# define noexcept throw ()
|
||||
#endif
|
||||
|
||||
struct A
|
||||
{
|
||||
virtual ~A () noexcept;
|
||||
const char *s;
|
||||
};
|
||||
|
||||
struct B: virtual A { };
|
||||
struct C: virtual A { }; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
|
||||
struct D: virtual B, virtual C
|
||||
{
|
||||
D (const char*);
|
||||
};
|
||||
|
||||
void sink (void*);
|
||||
void sink (D);
|
||||
|
||||
|
||||
// Verify that accesses to the table aren't diagnosed.
|
||||
void test_vtbl ()
|
||||
{
|
||||
sink (D (""));
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/* PR middle-end/98266 - bogus array subscript is partly outside array
|
||||
bounds on virtual inheritance
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
struct A
|
||||
{
|
||||
int ai, aj, aa[2];
|
||||
|
||||
virtual ~A ();
|
||||
};
|
||||
|
||||
struct B: virtual A { };
|
||||
struct C: virtual A { };
|
||||
|
||||
void sink (void*);
|
||||
|
||||
struct C1: virtual A
|
||||
{
|
||||
int c2i, c2j, c2a[2];
|
||||
|
||||
C1 ();
|
||||
~C1 ()
|
||||
{ // { dg-bogus "\\\[-Warray-bounds" }
|
||||
c2i = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
c2j = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
c2a[0] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
c2a[1] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
c2a[2] = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
};
|
||||
|
||||
struct D1: virtual B, virtual C1
|
||||
{
|
||||
D1 ();
|
||||
};
|
||||
|
||||
void sink (void*);
|
||||
|
||||
/* Verify that only out of bounds accesses to members of an ordinary base
|
||||
class are diagnosed. Use direct array accesses. */
|
||||
void test_vmem_base_ctor_arryaccess ()
|
||||
{
|
||||
D1 d2;
|
||||
sink (&d2);
|
||||
}
|
||||
|
||||
|
||||
struct C2: virtual A
|
||||
{
|
||||
int c3a[2];
|
||||
|
||||
C2 ();
|
||||
~C2 ()
|
||||
{ // { dg-bogus "\\\[-Warray-bounds" }
|
||||
int *p = c3a;
|
||||
*p++ = __LINE__;
|
||||
*p++ = __LINE__;
|
||||
*p++ = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
};
|
||||
|
||||
struct D2: virtual B, virtual C2
|
||||
{
|
||||
D2 ();
|
||||
};
|
||||
|
||||
/* Verify that only out of bounds accesses to members of an ordinary base
|
||||
class are diagnosed. Use pointer accesses. */
|
||||
void test_vmem_base_dtor_ptraccess ()
|
||||
{
|
||||
D2 d3;
|
||||
sink (&d3);
|
||||
}
|
||||
|
||||
|
||||
struct C3: virtual A // { dg-bogus "\\\[-Warray-bounds" }
|
||||
{
|
||||
int i, j, a[2];
|
||||
|
||||
C3 ();
|
||||
};
|
||||
|
||||
struct D3: virtual B, virtual C3
|
||||
{
|
||||
D3 ()
|
||||
{ // { dg-bogus "\\\[-Warray-bounds" }
|
||||
i = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
j = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
a[0] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
a[1] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
a[2] = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
};
|
||||
|
||||
/* Verify that only out of bounds accesses to members of an ordinary base
|
||||
class made in the ctor of a derived class are diagnosed. Use direct
|
||||
array accesses. */
|
||||
void test_vmem_derived_ctor_arryaccess ()
|
||||
{
|
||||
D3 d4;
|
||||
sink (&d4);
|
||||
}
|
||||
|
||||
|
||||
struct D4: virtual B, virtual C3
|
||||
{
|
||||
D4 ()
|
||||
{ // { dg-bogus "\\\[-Warray-bounds" }
|
||||
int *p = a;
|
||||
*p++ = __LINE__;
|
||||
*p++ = __LINE__;
|
||||
*p++ = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
};
|
||||
|
||||
/* Verify that only out of bounds accesses to members of an ordinary base
|
||||
class made in the ctor of a derived class are diagnosed. Use pointer
|
||||
accesses. */
|
||||
void test_vmem_derived_ctor_ptraccess ()
|
||||
{
|
||||
D4 d5;
|
||||
sink (&d5);
|
||||
}
|
||||
|
||||
|
||||
struct D5: virtual B, virtual C3 // { dg-bogus "\\\[-Warray-bounds" }
|
||||
{
|
||||
~D5 ()
|
||||
{
|
||||
i = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
j = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
a[0] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
a[1] = __LINE__; // { dg-bogus "\\\[-Warray-bounds" }
|
||||
a[2] = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
};
|
||||
|
||||
/* Verify that only out of bounds accesses to members of an ordinary base
|
||||
class made in the dtor of a derived class are diagnosed. Use pointer
|
||||
accesses. */
|
||||
void test_vmem_derived_dtor_arryaccess ()
|
||||
{
|
||||
D5 d6;
|
||||
sink (&d6);
|
||||
}
|
||||
|
||||
|
||||
struct D6: virtual B, virtual C3 // { dg-bogus "\\\[-Warray-bounds" }
|
||||
{
|
||||
~D6 ()
|
||||
{
|
||||
int *p = a;
|
||||
*p++ = __LINE__;
|
||||
*p++ = __LINE__;
|
||||
*p++ = __LINE__; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
};
|
||||
|
||||
/* Verify that only out of bounds accesses to members of an ordinary base
|
||||
class made in the dtor of a derived class are diagnosed. Use pointer
|
||||
accesses. */
|
||||
void test_vmem_derived_dtor_ptraccess ()
|
||||
{
|
||||
D6 d7;
|
||||
sink (&d7);
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/* PR middle-end/98266 - bogus array subscript is partly outside array
|
||||
bounds on virtual inheritance
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
void* operator new (__SIZE_TYPE__, void *p) { return p; }
|
||||
void* operator new[] (__SIZE_TYPE__, void *p) { return p; }
|
||||
|
||||
|
||||
struct A
|
||||
{
|
||||
virtual ~A ();
|
||||
int ai;
|
||||
};
|
||||
|
||||
struct B: virtual A { };
|
||||
|
||||
|
||||
// Exercise access to base members by ctor of the most derived class.
|
||||
|
||||
struct C1: virtual A // { dg-bogus "\\\[-Warray-bounds" }
|
||||
{
|
||||
int c1i;
|
||||
C1 ();
|
||||
};
|
||||
|
||||
struct D1: virtual B, virtual C1
|
||||
{
|
||||
D1 () { ai = 0; c1i = 1; };
|
||||
};
|
||||
|
||||
void sink (void*);
|
||||
|
||||
void nowarn_derived_ctor_access_decl ()
|
||||
{
|
||||
D1 d1;
|
||||
sink (&d1);
|
||||
}
|
||||
|
||||
void nowarn_derived_ctor_access_new ()
|
||||
{
|
||||
D1 *p = new D1;
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_derived_ctor_access_placement_new ()
|
||||
{
|
||||
char a[sizeof (D1)];
|
||||
D1 *p = new (a) D1;
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_derived_ctor_access_new_array ()
|
||||
{
|
||||
D1 *p = new D1[2];
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_derived_ctor_access_placement_new_array ()
|
||||
{
|
||||
char a[sizeof (D1) * 2];
|
||||
D1 *p = new (a) D1[2];
|
||||
sink (p);
|
||||
}
|
||||
|
||||
|
||||
// Exercise access to base members by ctor of the second most derived class.
|
||||
|
||||
struct C2: virtual A
|
||||
{
|
||||
int c2i;
|
||||
~C2 () { ai = 0; c2i = 1; } // { dg-bogus "\\\[-Warray-bounds"
|
||||
};
|
||||
|
||||
struct D2: virtual B, virtual C2
|
||||
{
|
||||
D2 ();
|
||||
};
|
||||
|
||||
void nowarn_base_dtor_access_decl ()
|
||||
{
|
||||
D2 d2;
|
||||
sink (&d2);
|
||||
}
|
||||
|
||||
void nowarn_base_dtor_access_new ()
|
||||
{
|
||||
D2 *p = new D2;
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_base_dtor_access_placement_new ()
|
||||
{
|
||||
char a[sizeof (D2)];
|
||||
D2 *p = new (a) D2;
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_base_dtor_access_new_array ()
|
||||
{
|
||||
D2 *p = new D2[2];
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_base_dtor_access_placement_new_array ()
|
||||
{
|
||||
char a[sizeof (D2) * 2];
|
||||
D2 *p = new (a) D2[2];
|
||||
sink (p);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/* PR middle-end/98266 - bogus array subscript is partly outside array
|
||||
bounds on virtual inheritance
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
void* operator new (__SIZE_TYPE__, void *p) { return p; }
|
||||
void* operator new[] (__SIZE_TYPE__, void *p) { return p; }
|
||||
|
||||
|
||||
struct A
|
||||
{
|
||||
int ai;
|
||||
virtual ~A ();
|
||||
};
|
||||
|
||||
struct B: virtual A { };
|
||||
|
||||
struct C: virtual A
|
||||
{
|
||||
int ci;
|
||||
C ();
|
||||
};
|
||||
|
||||
struct D1: virtual B, virtual C
|
||||
{
|
||||
/* The warning would ideally point to the assignment but instead points
|
||||
to the opening brace. */
|
||||
D1 ()
|
||||
{ // { dg-warning "\\\[-Warray-bounds" "brace" }
|
||||
ci = 0; // { dg-warning "\\\[-Warray-bounds" "assign" { xfail *-*-* } }
|
||||
}
|
||||
};
|
||||
|
||||
void sink (void*);
|
||||
|
||||
void warn_derived_ctor_access_new_decl ()
|
||||
{
|
||||
char a[sizeof (D1)]; // { dg-message "referencing 'a'" "note" }
|
||||
char *p = a;
|
||||
++p;
|
||||
D1 *q = new (p) D1;
|
||||
sink (q);
|
||||
}
|
||||
|
||||
void warn_derived_ctor_access_new_alloc ()
|
||||
{
|
||||
char *p = (char*)operator new (sizeof (D1)); // { dg-message "referencing an object of size \\d+ allocated by 'void\\\* operator new\\\(" "note" }
|
||||
++p;
|
||||
D1 *q = new (p) D1;
|
||||
sink (q);
|
||||
}
|
||||
|
||||
void warn_derived_ctor_access_new_array_decl ()
|
||||
{
|
||||
char b[sizeof (D1) * 2]; // { dg-message "referencing 'b'" "note" }
|
||||
char *p = b;
|
||||
++p;
|
||||
D1 *q = new (p) D1[2];
|
||||
sink (q);
|
||||
}
|
||||
|
||||
void warn_derived_ctor_access_new_array_alloc ()
|
||||
{
|
||||
char *p = new char[sizeof (D1) * 2]; // { dg-message "referencing an object of size \\d+ allocated by 'void\\\* operator new \\\[]\\\(" "note" }
|
||||
++p;
|
||||
D1 *q = new (p) D1[2];
|
||||
sink (q);
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/* PR middle-end/98266 - bogus array subscript is partly outside array
|
||||
bounds on virtual inheritance
|
||||
Same as Warray-bounds-19.C with nonvirtual inheritance.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
void* operator new (__SIZE_TYPE__, void *p) { return p; }
|
||||
void* operator new[] (__SIZE_TYPE__, void *p) { return p; }
|
||||
|
||||
|
||||
struct A
|
||||
{
|
||||
virtual ~A ();
|
||||
int ai;
|
||||
};
|
||||
|
||||
struct B: A { };
|
||||
|
||||
|
||||
// Exercise access to base members by ctor of the most derived class.
|
||||
|
||||
struct C1: A
|
||||
{
|
||||
int c1i;
|
||||
C1 ();
|
||||
};
|
||||
|
||||
struct D1: B, C1
|
||||
{
|
||||
D1 () { B::ai = 0; C1::ai = 1; c1i = 2; };
|
||||
};
|
||||
|
||||
void sink (void*);
|
||||
|
||||
void nowarn_derived_ctor_access_decl ()
|
||||
{
|
||||
D1 d1;
|
||||
sink (&d1);
|
||||
}
|
||||
|
||||
void nowarn_derived_ctor_access_new ()
|
||||
{
|
||||
D1 *p = new D1;
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_derived_ctor_access_placement_new ()
|
||||
{
|
||||
char a[sizeof (D1)];
|
||||
D1 *p = new (a) D1;
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_derived_ctor_access_new_array ()
|
||||
{
|
||||
D1 *p = new D1[2];
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_derived_ctor_access_placement_new_array ()
|
||||
{
|
||||
char a[sizeof (D1) * 2];
|
||||
D1 *p = new (a) D1[2];
|
||||
sink (p);
|
||||
}
|
||||
|
||||
|
||||
// Exercise access to base members by ctor of the second most derived class.
|
||||
|
||||
struct C2: A
|
||||
{
|
||||
int c2i;
|
||||
~C2 () { ai = 0; c2i = 1; }
|
||||
};
|
||||
|
||||
struct D2: B, C2
|
||||
{
|
||||
D2 ();
|
||||
};
|
||||
|
||||
void nowarn_base_dtor_access_decl ()
|
||||
{
|
||||
D2 d2;
|
||||
sink (&d2);
|
||||
}
|
||||
|
||||
void nowarn_base_dtor_access_new ()
|
||||
{
|
||||
D2 *p = new D2;
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_base_dtor_access_placement_new ()
|
||||
{
|
||||
char a[sizeof (D2)];
|
||||
D2 *p = new (a) D2;
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_base_dtor_access_new_array ()
|
||||
{
|
||||
D2 *p = new D2[2];
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void nowarn_base_dtor_access_placement_new_array ()
|
||||
{
|
||||
char a[sizeof (D2) * 2];
|
||||
D2 *p = new (a) D2[2];
|
||||
sink (p);
|
||||
}
|
Loading…
Reference in New Issue