On Thu, 26 Sep 2024, Jakub Jelinek wrote:

> On Thu, Aug 29, 2024 at 06:58:12PM -0400, David Malcolm wrote:
> > The following patch rewrites the internals of pp_format.
> 
> > The tokens and token lists are allocated on the chunk_obstack, and so
> > there's no additional heap activity required, with the memory reclaimed
> > when the chunk_obstack is freed after phase 3 of formatting.
> 
> > +static void *
> > +allocate_object (size_t sz, obstack &s)
> > +{
> > +  /* We must not be half-way through an object.  */
> > +  gcc_assert (obstack_base (&s) == obstack_next_free (&s));
> > +
> > +  obstack_grow (&s, obstack_base (&s), sz);
> > +  void *buf = obstack_finish (&s);
> > +  return buf;
> >  }
> 
> I think this is wrong.  I hoped it would be the reason of the
> unexpected libstdc++ warnings on certain architectures after
> seeing
> ==4027220== Source and destination overlap in memcpy(0x4627154, 0x4627154, 12)
> ==4027220==    at 0x404B93E: memcpy (vg_replace_strmem.c:1123)
> ==4027220==    by 0xAAD5618: allocate_object(unsigned int, obstack&) 
> (pretty-print.cc:1183)
> ==4027220==    by 0xAAD8C0E: operator new (pretty-print.cc:1210)
> ==4027220==    by 0xAAD8C0E: make (pretty-print-format-impl.h:305)
> ==4027220==    by 0xAAD8C0E: format_phase_1 (pretty-print.cc:1659)
> ==4027220==    by 0xAAD8C0E: pretty_printer::format(text_info&) 
> (pretty-print.cc:1618)
> ==4027220==    by 0xAAA840E: pp_format (pretty-print.h:583)
> ==4027220==    by 0xAAA840E: 
> diagnostic_context::report_diagnostic(diagnostic_info*) (diagnostic.cc:1260)
> ==4027220==    by 0xAAA8703: 
> diagnostic_context::diagnostic_impl(rich_location*, diagnostic_metadata 
> const*, diagnostic_option_id, char const*, char**, diagnostic_t) 
> (diagnostic.cc:1404)
> ==4027220==    by 0xAAB8682: warning(diagnostic_option_id, char const*, ...) 
> (diagnostic-global-context.cc:166)
> ==4027220==    by 0x97725F5: warn_deprecated_use(tree_node*, tree_node*) 
> (tree.cc:12485)
> ==4027220==    by 0x8B6694B: mark_used(tree_node*, int) (decl2.cc:6121)
> ==4027220==    by 0x8C9E25E: tsubst_expr(tree_node*, tree_node*, int, 
> tree_node*) [clone .part.0] (pt.cc:21626)
> ==4027220==    by 0x8C9E5E6: tsubst_expr(tree_node*, tree_node*, int, 
> tree_node*) [clone .part.0] (pt.cc:20935)
> ==4027220==    by 0x8C9E1D7: tsubst_expr(tree_node*, tree_node*, int, 
> tree_node*) [clone .part.0] (pt.cc:20424)
> ==4027220==    by 0x8C9DF2E: tsubst_expr(tree_node*, tree_node*, int, 
> tree_node*) [clone .part.0] (pt.cc:20496)
> ==4027220== 
> etc. valgrind warnings, unfortunately it is not, but still
> I think this is a bug.
> If the obstack has enough space in it, i.e. if obstack_room (&s) >= sz,
> then obstack_grow from obstack_base will copy uninitialized bytes
> through memcpy (obstack_base (&s), obstack_base (&s), sz);
> (which pedantically isn't valid due to the overlap, and so
> the reason why valgrind complains, but in reality I think most
> implementations can handle it fine, after all, we also use it for
> structure assignments which could have full or no overlap but never
> partial).
> If obstack_room (&s) < sz, then obstack_grow will first
> _obstack_newchunk (&s, sz); which will allocate new memory and
> copy the existing data of the object (but the above assertion
> guartantees it will copy 0 bytes) and then the memcpy copies
> sz bytes from the old base to the new (if unlucky, that could crash
> as there could be end of page and unmapped next page in between).
> 
> I think we should use obstack_blank instead of obstack_grow, which
> does everything obstack_grow does, except for the memcpy of the
> uninitialized data.
> 
> Bootstrapped/regtested on i686-linux, ok for trunk?

OK.

Thanks,
Richard.

> 2024-09-25  Jakub Jelinek  <ja...@redhat.com>
> 
>       * pretty-print.cc (allocate_object): Use obstack_blank rather than
>       obstack_grow.
> 
> --- gcc/pretty-print.cc.jj    2024-09-24 15:14:54.116162039 +0200
> +++ gcc/pretty-print.cc       2024-09-25 22:12:57.776029725 +0200
> @@ -1180,7 +1180,7 @@ allocate_object (size_t sz, obstack &s)
>    /* We must not be half-way through an object.  */
>    gcc_assert (obstack_base (&s) == obstack_next_free (&s));
>  
> -  obstack_grow (&s, obstack_base (&s), sz);
> +  obstack_blank (&s, sz);
>    void *buf = obstack_finish (&s);
>    return buf;
>  }
> 
> 
>       Jakub
> 
> 

Reply via email to