Follow up to bug 48279 comment 7 and 48279 comment 11. The following program segfaults with -std=f95 after printing the diagnostic: procedure get1 1 Error: Fortran 2003: PROCEDURE statement at (1) f951: internal compiler error: Segmentation fault Valgrind shows tons of errors, starting with: ==22545== Invalid read of size 8 ==22545== at 0x52FD8C: resolve_symbol (resolve.c:10004) ==22545== by 0x54BA76: traverse_ns (symbol.c:3379) ==22545== by 0x53919B: resolve_types (resolve.c:13261) ==22545== by 0x52E3D3: gfc_resolve (resolve.c:13357) The testcase: interface get procedure get1 end interface integer :: h call set1 (get (h)) contains subroutine set1 (a) integer, intent(in) :: a end subroutine integer function get1 (s) integer :: s end function end
Still present at revision 200128.
On my environment, the example from comment 0 compiles now without an ICE. $ gfortran-6 --version GNU Fortran (SUSE Linux) 6.1.1 20160502 [gcc-6-branch revision 235698] $ gfortran-6 -std=f95 pr48776.f90 pr48776.f90:6:18: procedure get1 1 Error: Fortran 2003: PROCEDURE statement at (1) pr48776.f90:9:14: integer :: h 1 Error: Procedure ‘h’ in generic interface 'get' at (1) is neither function nor subroutine pr48776.f90:10:13: call set1 (get (h)) 1 Error: There is no specific function for the generic ‘get’ at (1)
> On my environment, the example from comment 0 compiles now without an ICE. With 6.1.0, I get [Book15] f90/bug% gfortran pr48776.f90 -std=f95 pr48776.f90:2:18: procedure get1 1 Error: Fortran 2003: PROCEDURE statement at (1) ' (null):0: confused by earlier errors, bailing out or [Book15] f90/bug% gfortran pr48776.f90 -std=f95 pr48776.f90:2:18: procedure get1 1 Error: Fortran 2003: PROCEDURE statement at (1) pr48776.f90:5:14: integer :: h 1 Error: Procedure 'h' in generic interface 'get' at (1) is neither function nor subroutine pr48776.f90:6:13: call set1 (get (h)) 1 Error: There is no specific function for the generic 'get' at (1) So this PR seems to be another instance of non-deterministic error recovery.
Still many invalid reads using valgrind: Error: Fortran 2003: PROCEDURE statement at (1) ==13422== Invalid read of size 8 ==13422== at 0x6B2540: gfc_sym_get_dummy_args(gfc_symbol*) (symbol.c:4662) ==13422== by 0x695632: resolve_fl_procedure (resolve.c:11449) ==13422== by 0x695632: resolve_symbol(gfc_symbol*) (resolve.c:13884) ==13422== by 0x6AC8DB: do_traverse_symtree(gfc_symtree*, void (*)(gfc_symtree*), void (*)(gfc_symbol*)) (symbol.c:3646) ==13422== by 0x6971A2: resolve_types(gfc_namespace*) (resolve.c:15100) ==13422== by 0x692D4F: gfc_resolve(gfc_namespace*) [clone .part.48] (resolve.c:15210) ==13422== by 0x67E4DA: resolve_all_program_units (parse.c:5415) ==13422== by 0x67E4DA: gfc_parse_file() (parse.c:5658) ==13422== by 0x6BDDC5: gfc_be_parse_file() (f95-lang.c:229) ==13422== by 0xA7C2A1: compile_file() (toplev.c:594) ==13422== by 0x6005B3: do_compile (toplev.c:2067) ==13422== by 0x6005B3: toplev::main(int, char**) (toplev.c:2165) ==13422== by 0x6012A9: main (main.c:39) ==13422== Address 0x5f10998 is 120 bytes inside a block of size 304 free'd ==13422== at 0x4C2A37C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==13422== by 0x6B085A: gfc_restore_last_undo_checkpoint() (symbol.c:3177) ==13422== by 0x67431F: reject_statement() (parse.c:2358) ==13422== by 0x67457C: match_word(char const*, match (*)(), locus*) [clone .part.5] (parse.c:99) ==13422== by 0x679756: match_word (parse.c:511) ==13422== by 0x679756: decode_statement() (parse.c:511) ==13422== by 0x679AE0: next_free (parse.c:1118) ==13422== by 0x679AE0: next_statement() (parse.c:1352) ==13422== by 0x67A834: parse_interface (parse.c:3044) ==13422== by 0x67A834: parse_spec(gfc_statement) (parse.c:3389) ==13422== by 0x67D008: parse_progunit(gfc_statement) (parse.c:5087) ==13422== by 0x67E1D5: gfc_parse_file() (parse.c:5604) ==13422== by 0x6BDDC5: gfc_be_parse_file() (f95-lang.c:229) ==13422== by 0xA7C2A1: compile_file() (toplev.c:594) ==13422== by 0x6005B3: do_compile (toplev.c:2067) ==13422== by 0x6005B3: toplev::main(int, char**) (toplev.c:2165) ...
> So this PR seems to be another instance of non-deterministic error recovery. Yet another instance of ==2863==ERROR: AddressSanitizer: heap-use-after-free on address 0x613000002588 at pc 0x0001004e9eab bp 0x7ffeefbfe690 sp 0x7ffeefbfe688 READ of size 8 at 0x613000002588 thread T0 #0 0x1004e9eaa in gfc_sym_get_dummy_args(gfc_symbol*) symbol.c:5215 ... related to pr52622, pr84245, pr86657, and pr87908.
Can't reproduce with a recent master (14.0.0 20230814).
(In reply to Mikael Morin from comment #6) > Can't reproduce with a recent master (14.0.0 20230814). Sorry, missed the -std=f95 flag. Confirmed on recent master.
Created attachment 55800 [details] Draft patch This seems to work on comment #0. Not tested otherwise.
The master branch has been updated by Mikael Morin <mikael@gcc.gnu.org>: https://gcc.gnu.org/g:d58150452976c4ca65ddc811fac78ef956fa96b0 commit r14-3572-gd58150452976c4ca65ddc811fac78ef956fa96b0 Author: Mikael Morin <mikael@gcc.gnu.org> Date: Wed Aug 30 14:18:56 2023 +0200 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.
*** Bug 107923 has been marked as a duplicate of this bug. ***
Fixed for gcc 14. Closing.
The master branch has been updated by Mikael Morin <mikael@gcc.gnu.org>: https://gcc.gnu.org/g:6930e1f1055c39bea170c25f694f7301989e5d1d commit r14-8305-g6930e1f1055c39bea170c25f694f7301989e5d1d Author: Mikael Morin <mikael@gcc.gnu.org> Date: Fri Jan 19 18:47:36 2024 +0100 fortran: Restore current interface info on error [PR111291] This change is a followup to the fix for PR48776 (namely r14-3572-gd58150452976c4ca65ddc811fac78ef956fa96b0 AKA fortran: Restore interface to its previous state on error [PR48776]), which cleaned up new changes from interfaces upon error. Unfortunately, there is one case in that fix that is mishandled, visible on unexpected_interface.f90 with valgrind or an asan-instrumented gfortran. when an interface statement is found while parsing an interface body (which is invalid), the current interface is replaced by the one from the new statement, and as parsing continues, new procedures are added to the new interface, which has been rejected and freed, instead of the original one. This change restores the current interface pointer to its previous value on each rejected statement. PR fortran/48776 PR fortran/111291 gcc/fortran/ChangeLog: * parse.cc: Restore current interface to its previous value on error.