This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] have __builtin_object_size handle POINTER_PLUS with non-const offset
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: Martin Sebor <msebor at gmail dot com>
- Cc: Gcc Patch List <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 16 Sep 2016 12:29:49 +0200
- Subject: Re: [PATCH] have __builtin_object_size handle POINTER_PLUS with non-const offset
- Authentication-results: sourceware.org; auth=none
- References: <b60bf590-8063-5986-5cec-227f6a273017@gmail.com>
On Fri, Sep 16, 2016 at 5:29 AM, Martin Sebor <msebor@gmail.com> wrote:
> __builtin_object_size fails for POINTER_PLUS expressions involving
> non-constant offsets into objects of known size, causing GCC to fail
> to detect (and add instrumentation to prevent) buffer overflow in
> some basic cases such as the following:
>
> void f (unsigned i)
> {
> char d [3];
> memcpy (d + i, "abcdef", 5);
> }
>
> Since the size of the destination object is known, the call to memcpy
> is guaranteed to write past the end of it regardless of the value of
> the offset.
>
> The attached patch enhances __builtin_object_size to handle this case
> by returning the size of the whole object as the maximum and the size
> of the object minus T_MAX for the type of the offset T as the minimum.
>
> The patch also adds handling of ranges even though only very few cases
> benefit from it because the VRP pass runs after the object size pass.
> The one case that does appear to profit is when the value of the offset
> is constrained by its type, as in
>
> char a [1000];
>
> unsigned g (unsigned char i)
> {
> char *p = a + i;
> return __builtin_object_size (p, 2);
> }
>
> Here get_range_info () lets __builtin_object_size determine that
> the minimum number of bytes between (a + i) and (a + sizeof s) is
> sizeof a - UCHAR_MAX.
>
> The patch results in 64 more checking calls in a Binutils build than
> before.
I believe that you can't simply use the min/max of the ranges the way you
do nor can you assume zero for the minimum size as op1 might be
negative (for POINTER_PLUS_EXPR you need to interpret the offset
as signed).
Unless I completely misremember how tree-object-size.c works, of course.
Say,
char a[1000];
unsigned g (signed char i)
{
char *p = &a[10] + i;
return __builtin_object_size (p, 1);
}
range for i will be [-128, 127] but we'd like to return 1000 here I think.
Richard.
> Martin
>
> PS What would be a good way to arrange for the VRP pass to run before
> the object size pass so that the latter can benefit more from range
> information? As an experiment I added another instance of the VRP
> pass before the object size pass in passes.def and that worked, but
> I suspect that running VRP a third time isn't optimal.