Bug 48776 - ICE(segfault) after -std=f95 diagnostic error involving PROCEDURE
Summary: ICE(segfault) after -std=f95 diagnostic error involving PROCEDURE
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.7.0
: P3 minor
Target Milestone: ---
Assignee: Mikael Morin
URL:
Keywords: error-recovery, ice-on-invalid-code
: 107923 (view as bug list)
Depends on:
Blocks: 89891
  Show dependency treegraph
 
Reported: 2011-04-26 18:44 UTC by Tobias Burnus
Modified: 2024-01-20 15:50 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-08-09 00:00:00


Attachments
Draft patch (1.33 KB, patch)
2023-08-26 19:47 UTC, Mikael Morin
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Burnus 2011-04-26 18:44:45 UTC
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
Comment 1 Dominique d'Humieres 2013-06-16 13:13:23 UTC
Still present at revision 200128.
Comment 2 Gerhard Steinmetz 2016-05-03 19:21:13 UTC
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)
Comment 3 Dominique d'Humieres 2016-05-03 19:30:20 UTC
> 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.
Comment 4 Thomas Koenig 2016-08-09 21:08:32 UTC
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)

...
Comment 5 Dominique d'Humieres 2019-01-12 15:26:16 UTC
> 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.
Comment 6 Mikael Morin 2023-08-26 18:29:07 UTC
Can't reproduce with a recent master (14.0.0 20230814).
Comment 7 Mikael Morin 2023-08-26 18:30:39 UTC
(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.
Comment 8 Mikael Morin 2023-08-26 19:47:27 UTC
Created attachment 55800 [details]
Draft patch

This seems to work on comment #0.
Not tested otherwise.
Comment 9 GCC Commits 2023-08-30 12:20:23 UTC
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.
Comment 10 Mikael Morin 2023-08-30 19:38:16 UTC
*** Bug 107923 has been marked as a duplicate of this bug. ***
Comment 11 Mikael Morin 2023-08-30 19:39:42 UTC
Fixed for gcc 14.
Closing.
Comment 12 GCC Commits 2024-01-20 15:50:47 UTC
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.