Allow (void *) 0xdeadbeef accesses without warnings [PR99578]

Starting with GCC11 we keep emitting false positive -Warray-bounds or
-Wstringop-overflow etc. warnings on widely used *(type *)0x12345000
style accesses (or memory/string routines to such pointers).
This is a standard programming style supported by all C/C++ compilers
I've ever tried, used mostly in kernel or DSP programming, but sometimes
also together with mmap MAP_FIXED when certain things, often I/O registers
but could be anything else too are known to be present at fixed
addresses.

Such INTEGER_CST addresses can appear in code either because a user
used it like that (in which case it is fine) or because somebody used
pointer arithmetics (including &((struct whatever *)NULL)->field) on
a NULL pointer.  The middle-end warning code wrongly assumes that the
latter case is what is very likely, while the former is unlikely and
users should change their code.

The following patch adds a min-pagesize param defaulting to 4KB,
and treats INTEGER_CST addresses smaller than that as assumed results
of pointer arithmetics from NULL while addresses equal or larger than
that as expected user constant addresses.  For GCC 13 we can
represent results from pointer arithmetics on NULL using
&MEM[(void*)0 + offset] instead of (void*)offset INTEGER_CSTs.

2022-03-18  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/99578
	PR middle-end/100680
	PR tree-optimization/100834
	* params.opt (--param=min-pagesize=): New parameter.
	* pointer-query.cc
	(compute_objsize_r) <case ARRAY_REF>: Formatting fix.
	(compute_objsize_r) <case INTEGER_CST>: Use maximum object size instead
	of zero for pointer constants equal or larger than min-pagesize.

	* gcc.dg/tree-ssa/pr99578-1.c: New test.
	* gcc.dg/pr99578-1.c: New test.
	* gcc.dg/pr99578-2.c: New test.
	* gcc.dg/pr99578-3.c: New test.
	* gcc.dg/pr100680.c: New test.
	* gcc.dg/pr100834.c: New test.
This commit is contained in:
Jakub Jelinek 2022-03-18 18:58:06 +01:00
parent 0a0c2c3f06
commit 32ca611c42
8 changed files with 173 additions and 7 deletions

View File

@ -613,6 +613,10 @@ The maximum number of insns in loop header duplicated by the copy loop headers p
Common Joined UInteger Var(param_max_modulo_backtrack_attempts) Init(40) Param Optimization
The maximum number of backtrack attempts the scheduler should make when modulo scheduling a loop.
-param=min-pagesize=
Common Joined UInteger Var(param_min_pagesize) Init(4096) Param Optimization
Minimum page size for warning purposes.
-param=max-partial-antic-length=
Common Joined UInteger Var(param_max_partial_antic_length) Init(100) Param Optimization
Maximum length of partial antic set when performing tree pre optimization.

View File

@ -2243,7 +2243,7 @@ compute_objsize_r (tree ptr, gimple *stmt, bool addr, int ostype,
}
case ARRAY_REF:
return handle_array_ref (ptr, stmt, addr, ostype, pref, snlim, qry);
return handle_array_ref (ptr, stmt, addr, ostype, pref, snlim, qry);
case COMPONENT_REF:
return handle_component_ref (ptr, stmt, addr, ostype, pref, snlim, qry);
@ -2264,12 +2264,14 @@ compute_objsize_r (tree ptr, gimple *stmt, bool addr, int ostype,
}
case INTEGER_CST:
/* Pointer constants other than null are most likely the result
of erroneous null pointer addition/subtraction. Unless zero
is a valid address set size to zero. For null pointers, set
size to the maximum for now since those may be the result of
jump threading. */
if (integer_zerop (ptr))
/* Pointer constants other than null smaller than param_min_pagesize
might be the result of erroneous null pointer addition/subtraction.
Unless zero is a valid address set size to zero. For null pointers,
set size to the maximum for now since those may be the result of
jump threading. Similarly, for values >= param_min_pagesize in
order to support (type *) 0x7cdeab00. */
if (integer_zerop (ptr)
|| wi::to_widest (ptr) >= param_min_pagesize)
pref->set_max_size_range ();
else if (POINTER_TYPE_P (TREE_TYPE (ptr)))
{

View File

@ -0,0 +1,31 @@
/* PR middle-end/100680 */
/* { dg-do compile { target size32plus } } */
/* { dg-options "-O2 -Wstringop-overread" } */
struct s {
char a[8];
int i;
long l;
};
extern char ea[8];
static char sa[8] = { 1, 2, 3, 4 };
int
test (void)
{
const struct s *ps = (const struct s *) 0x12345678L;
if (__builtin_memcmp (ps->a, ps->a, 8))
return 0;
if (__builtin_memcmp (ps->a, ea, 8)) /* { dg-bogus "exceeds source size 0" } */
return 0;
if (__builtin_memcmp (ps->a, sa, 8)) /* { dg-bogus "exceeds source size 0" } */
return 0;
if (__builtin_memcmp (ps->a, "abcdABCD", 8)) /* { dg-bogus "exceeds source size 0" } */
return 0;
return 1;
}

View File

@ -0,0 +1,42 @@
/* PR tree-optimization/100834 */
/* { dg-do compile { target size32plus } } */
/* { dg-options "-O2 -Wall" } */
#define PAGE_SIZE 4096
#define STACK_SIZE PAGE_SIZE
union registers
{
struct
{
unsigned long r15, r14, r13, r12, r11, r10, r9, r8;
unsigned long rdi, rsi, rbp, unused, rbx, rdx, rcx, rax;
};
unsigned long by_index[16];
};
struct per_cpu
{
union
{
unsigned char stack[STACK_SIZE];
struct
{
unsigned char __fill[STACK_SIZE - sizeof (union registers)];
union registers guest_regs;
};
};
} __attribute__((aligned (PAGE_SIZE)));
static inline struct per_cpu *
this_cpu_data (void)
{
return (struct per_cpu *) 0xdeadbeef;
}
void
foo (void)
{
struct per_cpu *cpu_data = this_cpu_data ();
__builtin_memset (&cpu_data->guest_regs, 0, sizeof (cpu_data->guest_regs)); /* { dg-bogus "is out of the bounds" } */
}

View File

@ -0,0 +1,26 @@
/* PR middle-end/99578 */
/* { dg-do compile { target int32 } } */
/* { dg-options "-O2 -Warray-bounds" } */
struct S { int a, b[4]; };
struct T { int a, b[8192], c[4]; };
void
foo (struct S *p)
{
if (p) return;
__builtin_memset (p->b, 0, sizeof p->b); /* { dg-warning "offset \\\[0, 15\\\] is out of the bounds \\\[0, 0\\\]" } */
}
void
bar (struct T *p)
{
if (p) return;
__builtin_memset (p->c, 0, sizeof p->c); /* { dg-warning "offset \\\[0, 15\\\] is out of the bounds \\\[0, 0\\\]" "" { xfail *-*-* } } */
}
void
baz (void)
{
__builtin_memset ((void *) 0x8004, 0, 16); /* { dg-bogus "is out of the bounds" } */
}

View File

@ -0,0 +1,26 @@
/* PR middle-end/99578 */
/* { dg-do compile { target int32 } } */
/* { dg-options "-O2 -Wstringop-overflow" } */
struct S { int a, b[4]; };
struct T { int a, b[8192], c[4]; };
void
foo (struct S *p)
{
if (p) return;
__builtin_memset (p->b, 0, sizeof p->b); /* { dg-warning "writing 16 bytes into a region of size 0 overflows the destination" } */
}
void
bar (struct T *p)
{
if (p) return;
__builtin_memset (p->c, 0, sizeof p->c); /* { dg-warning "writing 16 bytes into a region of size 0 overflows the destination" "" { xfail *-*-* } } */
}
void
baz (void)
{
__builtin_memset ((void *) 0x8004, 0, 16); /* { dg-bogus "overflows the destination" } */
}

View File

@ -0,0 +1,13 @@
/* PR middle-end/99578 */
/* { dg-do compile { target size32plus } } */
/* { dg-options "-O2 -Wstringop-overread" } */
struct S { unsigned int s; };
extern struct S v;
extern void *memcpy (void *, const void *, __SIZE_TYPE__);
void
foo (void)
{
memcpy (&v, (void *)(0xe8ffc000), sizeof (struct S)); /* { dg-bogus "from a region of size 0" } */
}

View File

@ -0,0 +1,22 @@
/* PR middle-end/99578 */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
/* { dg-final { scan-tree-dump-not "&MEM" "optimized" } } */
/* { dg-final { scan-tree-dump-times "PHI <-?1\\\(\[0-9\]+\\\), -?1\\\(\[0-9\]+\\\)>" 2 "optimized" } } */
struct S { int a, b[4]; };
struct T { int a, b[8192], c[4]; };
int
foo (struct S *p)
{
if (p) return -1;
return p->b == (void *)4;
}
int
bar (struct T *p)
{
if (p) return -1;
return p->c == (void *)32772;
}