public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
From: Harald Anlauf <anlauf@gmx.de>
To: Mikael Morin <mikael@gcc.gnu.org>,
	gcc-patches@gcc.gnu.org, fortran@gcc.gnu.org
Subject: Re: [PATCH] fortran: Undo new symbols in all namespaces [PR110996]
Date: Mon, 11 Sep 2023 20:50:47 +0200	[thread overview]
Message-ID: <364c6a4a-b06d-41a0-8cdb-c446221672ee@gmx.de> (raw)
In-Reply-To: <20230911123845.1870133-1-mikael@gcc.gnu.org>

Hi Mikael,

On 9/11/23 14:38, Mikael Morin via Gcc-patches wrote:
> Hello,
>
> this fixes a memory management issue in the fortran frontend.
> I have included the (reduced) testcase from the PR, even if it wasn't failing
> here on x86_64 with the test harness.
> Tested on x86_64-pc-linux-gnu and manually checked the testcase with
> valgrind.
> OK for master?

nice fix!  This is OK for mainline.

Thanks for the patch!

Harald

> -- >8 --
>
> Remove new symbols from all namespaces they may have been added to in case a
> statement mismatches in the end and all the symbols referenced in it have to
> be reverted.
>
> This fixes memory errors and random internal compiler errors caused by
> a new symbol left with dangling pointers but not properly removed from the
> namespace at statement rejection.
>
> Before this change, new symbols were removed from their own namespace
> (their ns field) only.  This change additionally removes them from the
> namespaces pointed to by respectively the gfc_current_ns global variable,
> and the symbols' formal_ns field.
>
> 	PR fortran/110996
>
> gcc/fortran/ChangeLog:
>
> 	* gfortran.h (gfc_release_symbol): Set return type to bool.
> 	* symbol.cc (gfc_release_symbol): Ditto.  Return whether symbol was
> 	freed.
> 	(delete_symbol_from_ns): New, outline code from...
> 	(gfc_restore_last_undo_checkpoint): ... here.  Delete new symbols
> 	from two more namespaces.
>
> gcc/testsuite/ChangeLog:
>
> 	* gfortran.dg/pr110996.f90: New test.
> ---
>   gcc/fortran/gfortran.h                 |  2 +-
>   gcc/fortran/symbol.cc                  | 57 ++++++++++++++++++++------
>   gcc/testsuite/gfortran.dg/pr110996.f90 | 16 ++++++++
>   3 files changed, 62 insertions(+), 13 deletions(-)
>   create mode 100644 gcc/testsuite/gfortran.dg/pr110996.f90
>
> diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
> index 371f8743312..f4a1c106cea 100644
> --- a/gcc/fortran/gfortran.h
> +++ b/gcc/fortran/gfortran.h
> @@ -3514,7 +3514,7 @@ gfc_symtree *gfc_get_unique_symtree (gfc_namespace *);
>   gfc_user_op *gfc_get_uop (const char *);
>   gfc_user_op *gfc_find_uop (const char *, gfc_namespace *);
>   void gfc_free_symbol (gfc_symbol *&);
> -void gfc_release_symbol (gfc_symbol *&);
> +bool gfc_release_symbol (gfc_symbol *&);
>   gfc_symbol *gfc_new_symbol (const char *, gfc_namespace *);
>   gfc_symtree* gfc_find_symtree_in_proc (const char *, gfc_namespace *);
>   int gfc_find_symbol (const char *, gfc_namespace *, int, gfc_symbol **);
> diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc
> index 2cba2ea0bed..a6078bc608a 100644
> --- a/gcc/fortran/symbol.cc
> +++ b/gcc/fortran/symbol.cc
> @@ -3105,13 +3105,14 @@ gfc_free_symbol (gfc_symbol *&sym)
>   }
>
>
> -/* Decrease the reference counter and free memory when we reach zero.  */
> +/* Decrease the reference counter and free memory when we reach zero.
> +   Returns true if the symbol has been freed, false otherwise.  */
>
> -void
> +bool
>   gfc_release_symbol (gfc_symbol *&sym)
>   {
>     if (sym == NULL)
> -    return;
> +    return false;
>
>     if (sym->formal_ns != NULL && sym->refs == 2 && sym->formal_ns != sym->ns
>         && (!sym->attr.entry || !sym->module))
> @@ -3125,10 +3126,11 @@ gfc_release_symbol (gfc_symbol *&sym)
>
>     sym->refs--;
>     if (sym->refs > 0)
> -    return;
> +    return false;
>
>     gcc_assert (sym->refs == 0);
>     gfc_free_symbol (sym);
> +  return true;
>   }
>
>
> @@ -3649,6 +3651,29 @@ gfc_drop_last_undo_checkpoint (void)
>   }
>
>
> +/* Remove the reference to the symbol SYM in the symbol tree held by NS
> +   and free SYM if the last reference to it has been removed.
> +   Returns whether the symbol has been freed.  */
> +
> +static bool
> +delete_symbol_from_ns (gfc_symbol *sym, gfc_namespace *ns)
> +{
> +  if (ns == nullptr)
> +    return false;
> +
> +  /* The derived type is saved in the symtree with the first
> +     letter capitalized; the all lower-case version to the
> +     derived type contains its associated generic function.  */
> +  const char *sym_name = gfc_fl_struct (sym->attr.flavor)
> +			 ? gfc_dt_upper_string (sym->name)
> +			 : sym->name;
> +
> +  gfc_delete_symtree (&ns->sym_root, sym_name);
> +
> +  return gfc_release_symbol (sym);
> +}
> +
> +
>   /* Undoes all the changes made to symbols since the previous checkpoint.
>      This subroutine is made simpler due to the fact that attributes are
>      never removed once added.  */
> @@ -3703,15 +3728,23 @@ gfc_restore_last_undo_checkpoint (void)
>   	}
>         if (p->gfc_new)
>   	{
> -	  /* The derived type is saved in the symtree with the first
> -	     letter capitalized; the all lower-case version to the
> -	     derived type contains its associated generic function.  */
> -	  if (gfc_fl_struct (p->attr.flavor))
> -	    gfc_delete_symtree (&p->ns->sym_root,gfc_dt_upper_string (p->name));
> -          else
> -	    gfc_delete_symtree (&p->ns->sym_root, p->name);
> +	  bool freed = delete_symbol_from_ns (p, p->ns);
>
> -	  gfc_release_symbol (p);
> +	  /* If the symbol is a procedure (function or subroutine), remove
> +	     it from the procedure body namespace as well as from the outer
> +	     namespace.  */
> +	  if (!freed
> +	      && p->formal_ns != p->ns)
> +	    freed = delete_symbol_from_ns (p, p->formal_ns);
> +
> +	  /* If the formal_ns field has not been set yet, the previous
> +	     conditional does nothing.  In that case, we can assume that
> +	     gfc_current_ns is the procedure body namespace, and remove the
> +	     symbol from there.  */
> +	  if (!freed
> +	      && gfc_current_ns != p->ns
> +	      && gfc_current_ns != p->formal_ns)
> +	    freed = delete_symbol_from_ns (p, gfc_current_ns);
>   	}
>         else
>   	restore_old_symbol (p);
> diff --git a/gcc/testsuite/gfortran.dg/pr110996.f90 b/gcc/testsuite/gfortran.dg/pr110996.f90
> new file mode 100644
> index 00000000000..0e7551059a3
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/pr110996.f90
> @@ -0,0 +1,16 @@
> +! { dg-do compile }
> +!
> +! PR fortran/110996
> +! This example used to result in memory errors and sometimes internal compiler
> +! errors, because the rejection of the subroutine statement was causing the
> +! symbol D to be freed without also freeing the symbol C which remained in the
> +! namespace with a dangling pointer to D.
> +!
> +! Original testcase from Jeremy Bennett  <jeremy.bennett@embecosm.com>
> +
> +PROGRAM p
> +CONTAINS
> +  SUBROUTINE c(d) e { dg-error "Syntax error" }
> +  SUBROUTINE f
> +  END
> +END


      reply	other threads:[~2023-09-11 18:50 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-09-11 12:38 Mikael Morin
2023-09-11 18:50 ` Harald Anlauf [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=364c6a4a-b06d-41a0-8cdb-c446221672ee@gmx.de \
    --to=anlauf@gmx.de \
    --cc=fortran@gcc.gnu.org \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=mikael@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).