On Mon, 2017-12-04 at 18:05 -0700, Martin Sebor wrote:
> On 12/04/2017 01:58 PM, David Malcolm wrote:
> > On Mon, 2017-12-04 at 12:18 -0700, Martin Sebor wrote:
> > > On 12/04/2017 05:41 AM, Rainer Orth wrote:
> > > > Within test last week, 64-bit Solaris/SPARC bootstrap began to
> > > > fail:
> > > > 
> > > > /vol/gcc/src/hg/trunk/local/gcc/dbxout.c: In function 'bool
> > > > dbxout_block(tree, int, tree, int)':
> > > > /vol/gcc/src/hg/trunk/local/gcc/dbxout.c:3767:1: error: '%lu'
> > > > directive writing between 1 and 20 bytes into a region of size
> > > > 14
> > > > [-Werror=format-overflow=]
> > > >  dbxout_block (tree block, int depth, tree args, int
> > > > parent_blocknum)
> > > >  ^~~~~~~~~~~~
> > > > /vol/gcc/src/hg/trunk/local/gcc/dbxout.c:3767:1: note:
> > > > directive
> > > > argument in the range [0, 18446744073709551614]
> > > > In file included from ./tm.h:26,
> > > >                  from
> > > > /vol/gcc/src/hg/trunk/local/gcc/target.h:52,
> > > >                  from
> > > > /vol/gcc/src/hg/trunk/local/gcc/dbxout.c:72:
> > > > /vol/gcc/src/hg/trunk/local/gcc/config/sparc/sol2.h:353:11:
> > > > note:
> > > > 'std::sprintf' output between 8 and 27 bytes into a destination
> > > > of
> > > > size 20
> > > >    sprintf ((LABEL), "*.L%s%lu", (PREFIX), (unsigned
> > > > long)(NUM))
> > > >    ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > > > ~
> > > > /vol/gcc/src/hg/trunk/local/gcc/dbxout.c:3855:5: note: in
> > > > expansion
> > > > of macro 'ASM_GENERATE_INTERNAL_LABEL'
> > > >      ASM_GENERATE_INTERNAL_LABEL (buf, "LBB", parent_blocknum);
> > > >      ^~~~~~~~~~~~~~~~~~~~~~~~~~~
> > > > 
> > > > The line numbers are extremely confusing, to say the least,
> > > > though:
> > > > the
> > > > one in the error and the first note refer to the begin of the
> > > > function
> > > > definition and only the third note refers to the line of the
> > > > actual
> > > > error.
> > > 
> > > I agree it looks confusing.  It's the result of the interaction
> > > between macro tracking and inlining.
> > > 
> > > I think it's a general problem that affects many (though not all)
> > > warnings emitted out of the middle-end.  For instance, the
> > > example
> > > below results in similar output.  The output changes depending on
> > > whether or not _FORTIFY_SOURCE is defined.
> > > 
> > > #include <string.h>
> > > 
> > > #define FOO(d, s) strcpy (d, s)
> > > 
> > > void foo (char *d, const char *s) { FOO (d, s); }
> > > 
> > > void sink (char*);
> > > 
> > > void bar (void)
> > > {
> > >    char a[3];
> > > 
> > >    foo (a, "1234567");   // bug here
> > > 
> > >    sink (a);
> > > }
> > > 
> > > Without _FORTIFY_SOURCE:
> > > 
> > > d.c: In function ‘void bar()’:
> > > d.c:3:26: warning: ‘void* __builtin_memcpy(void*, const void*,
> > > long
> > > unsigned int)’ writing 8 bytes into a region of size 3 overflows
> > > the
> > > destination [-Wstringop-overflow=]
> > >   #define FOO(d, s) strcpy (d, s)
> > >                     ~~~~~~~^~~~~~
> > > d.c:5:37: note: in expansion of macro ‘FOO’
> > >   void foo (char *d, const char *s) { FOO (d, s); }
> > >                                       ^~~
> > > 
> > > If bar() were a bigger function with multiple calls to foo() it
> > > could be tricky to tell which of them caused the warning.
> > > 
> > > With _FORTIFY_SOURCE:
> > > 
> > > In file included from /usr/include/string.h:635,
> > >                   from d.c:1:
> > > In function ‘char* strcpy(char*, const char*)’,
> > >      inlined from ‘void bar()’ at d.c:5:37:
> > > /usr/include/bits/string3.h:110:33: warning: ‘void*
> > > __builtin___memcpy_chk(void*, const void*, long unsigned int,
> > > long
> > > unsigned int)’ writing 8 bytes into a region of size 3 overflows
> > > the
> > > destination [-Wstringop-overflow=]
> > >     return __builtin___strcpy_chk (__dest, __src, __bos
> > > (__dest));
> > >            ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > > 
> > > This suffers from the same problem as the first case: the line
> > > number of the offending call in bar() is missing.
> > > 
> > > In both cases the problem is compounded by the diagnostic, as
> > > a result of folding, referring to __builtin___memcpy_chk while
> > > the source code contains a call to strcpy.
> > > 
> > > I don't know nearly enough about the internals of the diagnostic
> > > subsystem to tell how difficult it might be to change the output
> > > to make it more readable.  David Malcolm is the expert on this
> > > area so he might have an idea what it would take.
> > 
> > [Did you mean to CC me on this, rather than dje?]
> 
> I meant you but I'm interested in all expert opinions/suggestions.
> 
> > I'm not as familiar as I could be on the existing inlining-tracking
> > implementation - so much so that, in ignorance, I wrote my own
> > version
> > of it earlier this year (doh!).
> > 
> > The warning implementation reads:
> > 
> > 3151                    warning_at (loc, opt,
> > 3152                                (integer_onep (range[0])
> > 3153                                 ? G_("%K%qD writing %E byte
> > into a region "
> > 3154                                      "of size %E overflows the
> > destination")
> > 3155                                 : G_("%K%qD writing %E bytes
> > into a region "
> > 3156                                      "of size %E overflows the
> > destination")),
> > 3157                                exp, get_callee_fndecl (exp),
> > range[0], objsize);
> > 
> > 
> > The inlining information is coming from that "%K" in the string,
> > which
> > leads to tree-pretty-print.c's percent_K_format being called for
> > "exp".
> >  This overwrites the "loc" provided for the warning_at with
> > EXPR_LOCATION of exp, and looks at TREE_BLOCK (exp), finding the
> > outermost containing block within its function, and writing it into
> > the
> > diagnostic_info's x_data.
> > 
> > This block is used by lhd_print_error_function (and C++'s
> > cp_print_error_function) to print the "inlined from" information.
> > 
> > This has several limitations:
> > 
> > (a) It would be better for the user to identify a specific
> > callsite,
> > rather than a function (or block), and print the source of the
> > callsite; we would then print something like:
> > 
> > (without _FORTIFY_SOURCE)
> > 
> > d.c: In function ‘void foo(char *d, const char *s)’,
> >     inlined from ‘bar’ at d.c:13:5:
> >    foo (a, "1234567");   // bug here
> >    ~~~~^~~~~~~~~~~~~~
> > d.c:3:26: warning: ‘void* __builtin_memcpy(void*, const void*, long
> > unsigned int)’ writing 8 bytes into a region of size 3 overflows
> > the destination [-Wstringop-overflow=]
> >   #define FOO(d, s) strcpy (d, s)
> >                     ~~~~~~~^~~~~~
> > d.c:5:37: note: in expansion of macro ‘FOO’
> >   void foo (char *d, const char *s) { FOO (d, s); }
> >                                       ^~~
> > 
> > (with _FORTIFY_SOURCE)
> > 
> > In file included from /usr/include/string.h:636,
> >                  from d.c:1:
> > In function ‘strcpy’,
> >     inlined from ‘foo’ at d.c:5:37,
> >   void foo (char *d, const char *s) { FOO (d, s); }
> >                                       ^~~
> >     inlined from ‘bar’ at d.c:13:5:
> >    foo (a, "1234567");   // bug here
> >    ~~~~^~~~~~~~~~~~~~
> > /usr/include/bits/string3.h:104:10: warning:
> > ‘__builtin___memcpy_chk’ writing 8 bytes into a region of size 3
> > overflows the destination [-Wstringop-overflow=]
> >    return __builtin___strcpy_chk (__dest, __src, __bos (__dest));
> >           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 
> Yes, that would be much better.  AFAICS, it actually already seems
> to work this way when foo() is declared both inline and artificial.
> 
> > How ought we to store the location of the callsite that's inlined?
> > (e.g. Would it be reasonable to add a TREE_BLOCK around a callsite
> > that's inlined, for that purpose?
> 
> It sounds reasonable to me.
> 
> > (b) That "%K" seems like something of a wart.  Would a family of
> > overloads like:
> > 
> >   warning_at (tree exp, int option, const char *etc, ...);
> > 
> > be more appropriate?  (though that requires locations for every
> > expression, I guess).
> 
> Given that the only position in the format string where %K makes
> sense the above would make sense.  %K is documented to take
> a CALL_EXPR argument.  There's now also a %G for a GIMPLE call
> argument, and presumably they already have a location.  A potential
> complication is that there are two locations: the location argument
> that's computed like so:
> 
>    location_t loc = tree_nonartificial_location (exp);
>    loc = expansion_point_location_if_in_system_header (loc);
> 
> and the CALL_EXPR argument to the %K directive.  If there are
> clients that need to suppress the warning from system headers
> and others that don't then a single API would be tricky to use
> in both kinds.  But I don't know of any such clients and
> disabling warnings coming out of system headers may not be
> necessary in the middle end.

> Martin

I've been poking at this file, and I think there's a cluster of bugs
related to how we handle and print chains of inlined callsites when
reporting middle-end diagnostics.

I've filed PR tree-optimization/83336 ("Issues with displaying inlining
chain for middle-end warnings")
  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83336
as a catch-all to cover the various issues; I'm adding more information
there, and am testing some fixes.

Dave

Reply via email to