aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/interface.cc
diff options
context:
space:
mode:
authorMikael Morin <mikael@gcc.gnu.org>2023-08-30 14:18:56 +0200
committerMikael Morin <mikael@gcc.gnu.org>2023-08-30 14:20:05 +0200
commitd58150452976c4ca65ddc811fac78ef956fa96b0 (patch)
tree416ad179572be1fe7560d2625dbf2428c031fdb9 /gcc/fortran/interface.cc
parentcaa7a99a052929d5970677c5b639e1fa5166e334 (diff)
downloadgcc-d58150452976c4ca65ddc811fac78ef956fa96b0.zip
gcc-d58150452976c4ca65ddc811fac78ef956fa96b0.tar.gz
gcc-d58150452976c4ca65ddc811fac78ef956fa96b0.tar.bz2
fortran: Restore interface to its previous state on error [PR48776]
Keep memory of the content of the current interface body being parsed and restore it to its previous state if it has been modified at the time a parse attempt fails. This fixes memory errors and random segmentation faults caused by dangling symbol pointers kept in interfaces' linked lists of symbols. If a parsing attempt fails and symbols are freed, they should also be removed from the current interface linked list. As the list of symbol is a linked list, and parsing only adds new symbols to the head of the list, all that is needed to track the previous content of the list is a pointer to its previous head. This adds such a pointer, and the restoration of the list of symbols to that pointer on error. PR fortran/48776 gcc/fortran/ChangeLog: * gfortran.h (gfc_drop_interface_elements_before): New prototype. (gfc_current_interface_head): Return a reference to the pointer. * interface.cc (gfc_current_interface_head): Ditto. (free_interface_elements_until): New function, generalizing gfc_free_interface. (gfc_free_interface): Use free_interface_elements_until. (gfc_drop_interface_elements_before): New function. * parse.cc (current_interface_ptr, previous_interface_head): New static variables. (current_interface_valid_p, get_current_interface_ptr): New functions. (decode_statement): Initialize previous_interface_head. (reject_statement): Restore current interface pointer to point to previous_interface_head. gcc/testsuite/ChangeLog: * gfortran.dg/interface_procedure_1.f90: New test.
Diffstat (limited to 'gcc/fortran/interface.cc')
-rw-r--r--gcc/fortran/interface.cc39
1 files changed, 34 insertions, 5 deletions
diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc
index ea82056..c01df04 100644
--- a/gcc/fortran/interface.cc
+++ b/gcc/fortran/interface.cc
@@ -78,14 +78,17 @@ along with GCC; see the file COPYING3. If not see
gfc_interface_info current_interface;
-/* Free a singly linked list of gfc_interface structures. */
+/* Free the leading members of the gfc_interface linked list given in INTR
+ up to the END element (exclusive: the END element is not freed).
+ If END is not nullptr, it is assumed that END is in the linked list starting
+ with INTR. */
-void
-gfc_free_interface (gfc_interface *intr)
+static void
+free_interface_elements_until (gfc_interface *intr, gfc_interface *end)
{
gfc_interface *next;
- for (; intr; intr = next)
+ for (; intr != end; intr = next)
{
next = intr->next;
free (intr);
@@ -93,6 +96,32 @@ gfc_free_interface (gfc_interface *intr)
}
+/* Free a singly linked list of gfc_interface structures. */
+
+void
+gfc_free_interface (gfc_interface *intr)
+{
+ free_interface_elements_until (intr, nullptr);
+}
+
+
+/* Update the interface pointer given by IFC_PTR to make it point to TAIL.
+ It is expected that TAIL (if non-null) is in the list pointed to by
+ IFC_PTR, hence the tail of it. The members of the list before TAIL are
+ freed before the pointer reassignment. */
+
+void
+gfc_drop_interface_elements_before (gfc_interface **ifc_ptr,
+ gfc_interface *tail)
+{
+ if (ifc_ptr == nullptr)
+ return;
+
+ free_interface_elements_until (*ifc_ptr, tail);
+ *ifc_ptr = tail;
+}
+
+
/* Change the operators unary plus and minus into binary plus and
minus respectively, leaving the rest unchanged. */
@@ -4953,7 +4982,7 @@ gfc_add_interface (gfc_symbol *new_sym)
}
-gfc_interface *
+gfc_interface *&
gfc_current_interface_head (void)
{
switch (current_interface.type)