This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Fix pr61848, linux kernel miscompile
- From: Andrew Pinski <pinskia at gmail dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, Andrew Pinski <pinskia at gmail dot com>
- Date: Sun, 14 Sep 2014 21:45:10 -0700
- Subject: Re: Fix pr61848, linux kernel miscompile
- Authentication-results: sourceware.org; auth=none
- References: <20140915040242 dot GG17693 at bubble dot grove dot modra dot org>
On Sun, Sep 14, 2014 at 9:02 PM, Alan Modra <amodra@gmail.com> wrote:
> This patch cures the linux kernel boot failure when compiled using
> trunk gcc. (Andrew, apologies for hijacking your bugzilla, I started
> work on this before finding the bugzilla..)
It is ok that you took over as it looks like you have a more complete
patch than I had.
Does it make sense to add a few testcases for the section attribute too?
Thanks,
Andrew Pinski
>
> At its heart, the problem is caused by merge_decls merging from the
> old decl to the new decl, then copying back to the old decl and
> discarding the new. When Jan moved some fields to the symtab,
> "copying back to the old decl" was lost for those fields. Really,
> it would be best if merge_decls was rewritten to merge everything to
> the kept decl, but here I'm just doing that for fields accessed via
> decl_with_vis.symtab_node.
>
> I also make a few other fixes
> 1) Trunk does not honour the last section attribute.
> extern char foo;
> char foo __attribute__ ((__section__(".machine")));
> char foo __attribute__ ((__section__(".mymachine")));
> results in a section of ".machine" for foo, rather than
> ".mymachine", the result for previous compilers back to 2.95 and
> possibly beyond.
> 1b) The comment about issuing "an error if the sections conflict"
> being done "later in decl_attributes" is seriously out of date.
> decl_attributes is called earlier on a fresh decl, so no error is
> issued (which I think makes the code in handle_section_attribute
> issuing this error, dead). It's been that way since at least 2.95.
> 2) TLS model attributes have never been merged as far as I can tell,
> except for #pragma omp threadprivate variables. I think
> extern int __thread x;
> int __thread x __attribute__ ((__tls_model__("local-exec")));
> ought to result in a local-exec "x" rather than a default model
> "x", but see the "isn't quite correct" comment below. Fixing that
> will, I think, require changing enum tls_model to make
> TLS_MODEL_REAL different to TLS_MODEL_GLOBAL_DYNAMIC (which will
> also fix the mismatch between enum tls_model and tls_model_names[]).
> 3) The patch hunks below in cp/decl.c that just s/olddecl/newdecl/
> are to fix "if (TREE_CODE (newdecl) == FUNCTION_DECL) ...
> else switch (TREE_CODE (olddecl))" which looks horrible to me.
> It's really just cosmetic since we know
> TREE_CODE (newdecl) == TREE_CODE (olddecl) at this point.
>
> Bootstrapped and regression tested x86_64-linux. OK to apply?
>
> gcc/c/
> PR middle-end/61848
> * c-decl.c (merge_decls): Don't merge section name or tls model
> to newdecl symtab node, instead merge to olddecl. Override
> existing olddecl section name. Set tls_model for all thread-local
> vars, not just OMP thread-private ones. Remove incorrect comment.
> gcc/cp/
> PR middle-end/61848
> * decl.c (merge_decls): Don't merge section name, comdat group or
> tls model to newdecl symtab node, instead merge to olddecl.
> Override existing olddecl section name. Set tls_model for all
> thread-local vars, not just OMP thread-private ones. Remove
> incorrect comment.
>
> Index: gcc/c/c-decl.c
> ===================================================================
> --- gcc/c/c-decl.c (revision 215233)
> +++ gcc/c/c-decl.c (working copy)
> @@ -2292,22 +2292,10 @@ merge_decls (tree newdecl, tree olddecl, tree newt
>
> /* Merge the threadprivate attribute. */
> if (TREE_CODE (olddecl) == VAR_DECL && C_DECL_THREADPRIVATE_P (olddecl))
> - {
> - set_decl_tls_model (newdecl, DECL_TLS_MODEL (olddecl));
> - C_DECL_THREADPRIVATE_P (newdecl) = 1;
> - }
> + C_DECL_THREADPRIVATE_P (newdecl) = 1;
>
> if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS))
> {
> - /* Merge the section attribute.
> - We want to issue an error if the sections conflict but that
> - must be done later in decl_attributes since we are called
> - before attributes are assigned. */
> - if ((DECL_EXTERNAL (olddecl) || TREE_PUBLIC (olddecl) || TREE_STATIC (olddecl))
> - && DECL_SECTION_NAME (newdecl) == NULL
> - && DECL_SECTION_NAME (olddecl))
> - set_decl_section_name (newdecl, DECL_SECTION_NAME (olddecl));
> -
> /* Copy the assembler name.
> Currently, it can only be defined in the prototype. */
> COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
> @@ -2517,6 +2505,20 @@ merge_decls (tree newdecl, tree olddecl, tree newt
> (char *) newdecl + sizeof (struct tree_decl_common),
> tree_code_size (TREE_CODE (olddecl)) - sizeof (struct tree_decl_common));
> olddecl->decl_with_vis.symtab_node = snode;
> +
> + if ((DECL_EXTERNAL (olddecl)
> + || TREE_PUBLIC (olddecl)
> + || TREE_STATIC (olddecl))
> + && DECL_SECTION_NAME (newdecl) != NULL)
> + set_decl_section_name (olddecl, DECL_SECTION_NAME (newdecl));
> +
> + /* This isn't quite correct for something like
> + int __thread x attribute ((tls_model ("local-exec")));
> + extern int __thread x;
> + as we'll lose the "local-exec" model. */
> + if (TREE_CODE (olddecl) == VAR_DECL
> + && DECL_THREAD_LOCAL_P (newdecl))
> + set_decl_tls_model (olddecl, DECL_TLS_MODEL (newdecl));
> break;
> }
>
> Index: gcc/cp/decl.c
> ===================================================================
> --- gcc/cp/decl.c (revision 215233)
> +++ gcc/cp/decl.c (working copy)
> @@ -1970,7 +1970,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool
> if (!DECL_LANG_SPECIFIC (newdecl))
> retrofit_lang_decl (newdecl);
>
> - set_decl_tls_model (newdecl, DECL_TLS_MODEL (olddecl));
> CP_DECL_THREADPRIVATE_P (newdecl) = 1;
> }
> }
> @@ -2033,15 +2032,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool
> }
> }
>
> - /* Merge the section attribute.
> - We want to issue an error if the sections conflict but that must be
> - done later in decl_attributes since we are called before attributes
> - are assigned. */
> - if ((DECL_EXTERNAL (olddecl) || TREE_PUBLIC (olddecl) || TREE_STATIC (olddecl))
> - && DECL_SECTION_NAME (newdecl) == NULL
> - && DECL_SECTION_NAME (olddecl) != NULL)
> - set_decl_section_name (newdecl, DECL_SECTION_NAME (olddecl));
> -
> if (TREE_CODE (newdecl) == FUNCTION_DECL)
> {
> DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
> @@ -2086,19 +2076,6 @@ duplicate_decls (tree newdecl, tree olddecl, bool
> /* Merge the storage class information. */
> merge_weak (newdecl, olddecl);
>
> - if ((TREE_CODE (olddecl) == FUNCTION_DECL || TREE_CODE (olddecl) == VAR_DECL)
> - && (DECL_EXTERNAL (olddecl) || TREE_PUBLIC (olddecl) || TREE_STATIC (olddecl))
> - && DECL_ONE_ONLY (olddecl))
> - {
> - struct symtab_node *symbol;
> - if (TREE_CODE (olddecl) == FUNCTION_DECL)
> - symbol = cgraph_node::get_create (newdecl);
> - else
> - symbol = varpool_node::get_create (newdecl);
> - symbol->set_comdat_group (symtab_node::get
> - (olddecl)->get_comdat_group ());
> - }
> -
> DECL_DEFER_OUTPUT (newdecl) |= DECL_DEFER_OUTPUT (olddecl);
> TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
> TREE_STATIC (olddecl) = TREE_STATIC (newdecl) |= TREE_STATIC (olddecl);
> @@ -2452,12 +2429,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool
> }
> else
> {
> - size_t size = tree_code_size (TREE_CODE (olddecl));
> + size_t size = tree_code_size (TREE_CODE (newdecl));
>
> memcpy ((char *) olddecl + sizeof (struct tree_common),
> (char *) newdecl + sizeof (struct tree_common),
> sizeof (struct tree_decl_common) - sizeof (struct tree_common));
> - switch (TREE_CODE (olddecl))
> + switch (TREE_CODE (newdecl))
> {
> case LABEL_DECL:
> case VAR_DECL:
> @@ -2469,7 +2446,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool
> {
> struct symtab_node *snode = NULL;
>
> - if (TREE_CODE (olddecl) == VAR_DECL
> + if (TREE_CODE (newdecl) == VAR_DECL
> && (TREE_STATIC (olddecl) || TREE_PUBLIC (olddecl) || DECL_EXTERNAL (olddecl)))
> snode = symtab_node::get (olddecl);
> memcpy ((char *) olddecl + sizeof (struct tree_decl_common),
> @@ -2476,7 +2453,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool
> (char *) newdecl + sizeof (struct tree_decl_common),
> size - sizeof (struct tree_decl_common)
> + TREE_CODE_LENGTH (TREE_CODE (newdecl)) * sizeof (char *));
> - if (TREE_CODE (olddecl) == VAR_DECL)
> + if (TREE_CODE (newdecl) == VAR_DECL)
> olddecl->decl_with_vis.symtab_node = snode;
> }
> break;
> @@ -2488,6 +2465,38 @@ duplicate_decls (tree newdecl, tree olddecl, bool
> break;
> }
> }
> +
> + if (TREE_CODE (newdecl) == FUNCTION_DECL
> + || TREE_CODE (newdecl) == VAR_DECL)
> + {
> + if (DECL_EXTERNAL (olddecl)
> + || TREE_PUBLIC (olddecl)
> + || TREE_STATIC (olddecl))
> + {
> + /* Merge the section attribute.
> + We want to issue an error if the sections conflict but that must be
> + done later in decl_attributes since we are called before attributes
> + are assigned. */
> + if (DECL_SECTION_NAME (newdecl) != NULL)
> + set_decl_section_name (olddecl, DECL_SECTION_NAME (newdecl));
> +
> + if (DECL_ONE_ONLY (newdecl))
> + {
> + struct symtab_node *oldsym, *newsym;
> + if (TREE_CODE (olddecl) == FUNCTION_DECL)
> + oldsym = cgraph_node::get_create (olddecl);
> + else
> + oldsym = varpool_node::get_create (olddecl);
> + newsym = symtab_node::get (newdecl);
> + oldsym->set_comdat_group (newsym->get_comdat_group ());
> + }
> + }
> +
> + if (TREE_CODE (newdecl) == VAR_DECL
> + && DECL_THREAD_LOCAL_P (newdecl))
> + set_decl_tls_model (olddecl, DECL_TLS_MODEL (newdecl));
> + }
> +
> DECL_UID (olddecl) = olddecl_uid;
> if (olddecl_friend)
> DECL_FRIEND_P (olddecl) = 1;
>
> --
> Alan Modra
> Australia Development Lab, IBM