On Tue, Jun 23, 2020 at 12:22 AM Martin Sebor via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> On 6/22/20 12:55 PM, Jason Merrill wrote:
> > On 6/22/20 1:25 PM, Martin Sebor wrote:
> >> The attached fix parallels the one for the equivalent C bug 95580
> >> where the pretty printers don't correctly handle MEM_REF arguments
> >> with type void* or other pointers to an incomplete type.
> >>
> >> The incorrect handling was exposed by the recent change to
> >> -Wuninitialized which includes such expressions in diagnostics.
> >
> >> +        if (tree size = TYPE_SIZE_UNIT (TREE_TYPE (argtype)))
> >> +          if (!integer_onep (size))
> >> +            {
> >> +              pp_cxx_left_paren (pp);
> >> +              dump_type (pp, ptr_type_node, flags);
> >> +              pp_cxx_right_paren (pp);
> >> +            }
> >
> > Don't we want to print the cast if the pointer target type is incomplete?
>
> I suppose, yes, although after some more testing I think what should
> be output is the type of the access.  The target pointer type isn't
> meaningful (at least not in this case).
>
> Here's what the warning looks like in C for the test case in
> gcc.dg/pr95580.c:
>
>    warning: ‘*((void *)(p)+1)’ may be used uninitialized
>
> and like this in C++:
>
>    warning: ‘*(p +1)’ may be used uninitialized
>
> The +1 is a byte offset, which is correct given that incrementing
> a void* in GCC is the same as adding 1 to the byte address, but
> dereferencing a void* doesn't correspond to what's going on in
> the source.
>
> Even for a complete type (with size greater than 1), printing
> the type of the argument plus a byte offset is wrong.  It ends
> up with this for the C++ test case from 95768:
>
>    warning: ‘*((int*)<unknown> +4)’ is used uninitialized
>
> when the access is actually ‘*((int*)<unknown> +1)’
>
> So it seems to me for MEM_REF, to make the output meaningful,
> it's the type of the access (i.e., the MEM_REF type) that should
> be printed here, and the offset should either be in elements of
> the accessed type, i.e.,
>
>    warning: ‘*((int*)<unknown> +1)’ is used uninitialized
>
> or, if the access is misaligned, the argument should first be
> cast to char*, the offset added, and the result then cast to
> the access type, like this:
>
>    warning: ‘*(T*)((char*)<unknown> +1)’ is used uninitialized
>
> The attached revised and less than fully tested patch implements
> this for C++ only for now.  If we agree on this approach I'll see
> about making the corresponding change in C.

Note that there is no C/C++ way of fully expressing MEM_REF
semantics.  __MEM <int> ((T *)p + 1) is not actually
*(int *)((char *)p + 1) because that does not reflect that the
effective type of the lvalue when TBAA is concerned is 'T'
rather than 'int'.  Note for MEM_REF the offset is always
a constant byte offset but it indeed does not have to be a
multiple of the MEM_REF type size.

I wonder whether printing the MEM_REF in full provides
any real diagnostic value in the more "obfuscated" cases.

I'd also not print <unknown> but <register>.

Richard.

> Martin

Reply via email to