When running the testsuite with a compiler sanitized with -fsanitize=hwaddress (HWASAN sanitizer which is not yet committed upstream) I saw the error below. The error comes from the testsuite running `pr93337.f90`. It is complaining that `gfc_find_derived_vtab` is attempting to access an 8 byte chunk of data 88 bytes after a region that is only 48 bytes long. That seems to be coming from the access of `derived->attr.pdt_template` (which is a one-bit field in the byte 92 bytes into a `gfc_symbol` structure). According to the dump the 48 byte long structure is allocated in `gfc_new_charlen`. This function only ever sets the `cl` alternative of the union in a `gfc_typespec`. I've inlined a GDB session demonstrating the mis-use under the HWASAN dump. ==25394==ERROR: HWAddressSanitizer: tag-mismatch on address 0xefdfffff79d8 at pc 0x0000006a8560 READ of size 8 at 0xefdfffff79d8 tags: 58/ff (ptr/mem) in thread T0 #0 0x6a855c in SigTrap<3> ../../../../gcc-source/libsanitizer/hwasan/hwasan_checks.h:27 #1 0x6a855c in CheckAddress<(__hwasan::ErrorAction)0, (__hwasan::AccessType)0, 3> ../../../../gcc-source/libsanitizer/hwasan/hwasan_checks.h:88 #2 0x6a855c in __hwasan_load8 ../../../../gcc-source/libsanitizer/hwasan/hwasan.cpp:454 #3 0x6ff654 in gfc_find_derived_vtab(gfc_symbol*) ../../gcc-source/gcc/fortran/class.c:2269 #4 0x707498 in gfc_find_vtab(gfc_typespec*) ../../gcc-source/gcc/fortran/class.c:2908 #5 0x707498 in gfc_find_vtab(gfc_typespec*) ../../gcc-source/gcc/fortran/class.c:2898 #6 0x7a7578 in gfc_match_assignment() ../../gcc-source/gcc/fortran/match.c:1393 #7 0x80d53c in match_word ../../gcc-source/gcc/fortran/parse.c:65 #8 0x80d53c in decode_statement ../../gcc-source/gcc/fortran/parse.c:361 #9 0x812f28 in next_free ../../gcc-source/gcc/fortran/parse.c:1280 #10 0x812f28 in next_statement ../../gcc-source/gcc/fortran/parse.c:1512 #11 0x816190 in parse_spec ../../gcc-source/gcc/fortran/parse.c:3923 #12 0x819948 in parse_progunit ../../gcc-source/gcc/fortran/parse.c:5853 #13 0x81c02c in gfc_parse_file() ../../gcc-source/gcc/fortran/parse.c:6394 #14 0x898d98 in gfc_be_parse_file ../../gcc-source/gcc/fortran/f95-lang.c:212 #15 0x152ac7c in compile_file ../../gcc-source/gcc/toplev.c:458 #16 0x69d114 in do_compile ../../gcc-source/gcc/toplev.c:2320 #17 0x69d114 in toplev::main(int, char**) ../../gcc-source/gcc/toplev.c:2459 #18 0x6a0218 in main ../../gcc-source/gcc/main.c:39 #19 0xffffa03c38dc in __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x1f8dc) [0xefdfffff79c0,0xefdfffff7a00) is a small allocated heap chunk; size: 64 offset: 24 0xefdfffff79d8 is located 40 bytes to the right of 48-byte region [0xefdfffff7980,0xefdfffff79b0) allocated here: #0 0x6a9d40 in __sanitizer_calloc ../../../../gcc-source/libsanitizer/hwasan/hwasan_interceptors.cpp:138 #1 0x2d1ebbc in xcalloc ../../gcc-source/libiberty/xmalloc.c:162 #2 0x8831a0 in gfc_new_charlen(gfc_namespace*, gfc_charlen*) ../../gcc-source/gcc/fortran/symbol.c:3964 #3 0x7146ec in gfc_match_char_spec(gfc_typespec*) ../../gcc-source/gcc/fortran/decl.c:3478 #4 0x71e324 in gfc_match_decl_type_spec(gfc_typespec*, int) ../../gcc-source/gcc/fortran/decl.c:4169 #5 0x7220d8 in gfc_match_data_decl() ../../gcc-source/gcc/fortran/decl.c:6129 #6 0x80d6b0 in match_word ../../gcc-source/gcc/fortran/parse.c:65 #7 0x80d6b0 in decode_statement ../../gcc-source/gcc/fortran/parse.c:376 #8 0x812f28 in next_free ../../gcc-source/gcc/fortran/parse.c:1280 #9 0x812f28 in next_statement ../../gcc-source/gcc/fortran/parse.c:1512 #10 0x816600 in parse_derived ../../gcc-source/gcc/fortran/parse.c:3343 #11 0x816600 in parse_spec ../../gcc-source/gcc/fortran/parse.c:3884 #12 0x819948 in parse_progunit ../../gcc-source/gcc/fortran/parse.c:5853 #13 0x81c02c in gfc_parse_file() ../../gcc-source/gcc/fortran/parse.c:6394 #14 0x898d98 in gfc_be_parse_file ../../gcc-source/gcc/fortran/f95-lang.c:212 #15 0x152ac7c in compile_file ../../gcc-source/gcc/toplev.c:458 #16 0x69d114 in do_compile ../../gcc-source/gcc/toplev.c:2320 #17 0x69d114 in toplev::main(int, char**) ../../gcc-source/gcc/toplev.c:2459 #18 0x6a0218 in main ../../gcc-source/gcc/main.c:39 #19 0xffffa03c38dc in __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x1f8dc) #20 0x6a3e5c (/home/ubuntu/working-directory/gcc-hwasan-install/libexec/gcc/aarch64-unknown-linux-gnu/11.0.0/f951+0x6a3e5c) Thread: T0 0xeffe00002000 stack: [0xfffffabad000,0xfffffebad000) sz: 67108864 tls: [0xffffa060b000,0xffffa060b850) Memory tags around the buggy address (one tag corresponds to 16 bytes): 0xfefcfffff710: b5 b5 b5 08 1a 1a 1a 1a 47 47 47 08 2b 2b 2b 08 0xfefcfffff720: 79 79 79 08 ad ad ad ad 77 77 77 08 42 42 42 08 0xfefcfffff730: 70 70 70 70 93 93 93 08 36 36 36 36 19 19 19 08 0xfefcfffff740: 6e 6e 6e 6e c2 c2 c2 08 29 29 29 08 9f 9f 9f 9f 0xfefcfffff750: ce ce ce 08 3c 3c 3c ed d1 d1 d1 08 2a 2a 2a 08 0xfefcfffff760: bb bb bb bb e9 e9 e9 08 2c 2c 2c 08 b4 b4 b4 b4 0xfefcfffff770: 33 33 33 08 0d 0d 0d 08 ec ec ec ec 29 29 29 08 0xfefcfffff780: bf bf bf 08 f9 f9 f9 f9 f0 f0 f0 08 01 01 01 08 =>0xfefcfffff790: fc fc fc fc f0 f0 f0 08 58 58 58 81 ff [ff] ff 08 0xfefcfffff7a0: a8 a8 a8 08 83 83 83 83 f3 f3 f3 08 9e 9e 9e 08 0xfefcfffff7b0: bf bf bf 08 7f 7f 7f 7f cc cc 04 9e 43 43 43 43 0xfefcfffff7c0: c4 c4 c4 c4 12 12 12 b5 36 36 36 36 2d 2d 2d 2d 0xfefcfffff7d0: 65 65 65 65 cc cc cc cc 4c 4c 4c 4c 78 78 78 0e 0xfefcfffff7e0: d1 d1 d1 d1 f5 f5 f5 f5 57 57 57 08 b0 b0 b0 08 0xfefcfffff7f0: 5e 5e 5e 08 49 49 49 08 7c 7c 7c 08 85 85 85 08 0xfefcfffff800: 63 63 63 08 7d 7d 7d 08 0d 0d 0d 08 71 71 71 08 0xfefcfffff810: 06 06 08 97 74 74 74 08 bb bb bb 08 aa aa aa 08 Tags for short granules around the buggy address (one tag corresponds to 16 bytes): 0xfefcfffff780: .. .. .. bf .. .. .. .. .. .. .. f0 f0 00 00 01 =>0xfefcfffff790: .. .. .. .. .. .. .. f0 .. .. .. .. .. [..] .. ff 0xfefcfffff7a0: .. .. .. a8 .. .. .. .. .. .. .. f3 .. .. .. 9e See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tags SUMMARY: HWAddressSanitizer: tag-mismatch ../../../../gcc-source/libsanitizer/hwasan/hwasan_checks.h:27 in SigTrap<3> GDB session demonstrating this happening (to demonstrate that this does seem to be misusing a `gfc_charlen*` as a `gfc_symbol *`). ubuntu@ubuntu:~/working-directory$ ./gcc-hwasan-install/bin/gfortran gcc-source/gcc/testsuite/gfortran.dg/pr93337.f90 -O -pedantic-errors -S -o - -wrapper gdb,-q,--args Reading symbols from /home/ubuntu/working-directory/gcc-hwasan-install/libexec/gcc/aarch64-unknown-linux-gnu/11.0.0/f951...done. (gdb) break decl.c:3516 if $_any_caller_is("gfc_match_decl_type_spec") Breakpoint 1 at 0x714814: file ../../gcc-source/gcc/fortran/decl.c, line 3516. (gdb) run Starting program: /home/ubuntu/working-directory/gcc-hwasan-install/libexec/gcc/aarch64-unknown-linux-gnu/11.0.0/f951 gcc-source/gcc/testsuite/gfortran.dg/pr93337.f90 -quiet -dumpbase pr93337.f90 -dumpbase-ext .f90 -mlittle-endian -mabi=lp64 -O -pedantic-errors -o - -fintrinsic-modules-path /home/ubuntu/working-directory/gcc-hwasan-install/lib/gcc/aarch64-unknown-linux-gnu/11.0.0/finclude [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1". .arch armv8-a .file "pr93337.f90" Breakpoint 1, gfc_match_char_spec (ts=ts@entry=0x4028c58 <current_ts>) at ../../gcc-source/gcc/fortran/decl.c:3516 3516 ts->u.cl = cl; (gdb) print cl $1 = (gfc_charlen *) 0x3100efdfffff3440 (gdb) break gfc_find_derived_vtab if (void*)derived == (void*)$1 Breakpoint 2 at 0x6ff370: file ../../gcc-source/gcc/fortran/class.c, line 2262. (gdb) cont Continuing. Breakpoint 2, gfc_find_derived_vtab (derived=derived@entry=0x3100efdfffff3440) at ../../gcc-source/gcc/fortran/class.c:2262 2262 { (gdb)
Confirmed, one can see it in valgrind as well: ==1018== Invalid read of size 1 ==1018== at 0x7F10BB: gfc_find_derived_vtab(gfc_symbol*) (class.c:2269) ==1018== by 0x8484F3: gfc_match_assignment() (match.c:1393) ==1018== by 0x86F742: match_word (parse.c:65) ==1018== by 0x86F742: decode_statement() (parse.c:361) ==1018== by 0x874C14: next_free (parse.c:1315) ==1018== by 0x874C14: next_statement() (parse.c:1547) ==1018== by 0x87675C: parse_spec(gfc_statement) (parse.c:3962) ==1018== by 0x87949C: parse_progunit(gfc_statement) (parse.c:5892) ==1018== by 0x87AB80: gfc_parse_file() (parse.c:6433) ==1018== by 0x8CC54F: gfc_be_parse_file() (f95-lang.c:212) ==1018== by 0xE4C123: compile_file() (toplev.c:458) ==1018== by 0x7D2D91: do_compile (toplev.c:2327) ==1018== by 0x7D2D91: toplev::main(int, char**) (toplev.c:2466) ==1018== by 0x7D6B5E: main (main.c:39) ==1018== Address 0x51264ae is 18 bytes before a block of size 264 free'd ==1018== at 0x48399AB: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==1018== by 0x7DE7EF: gfc_match_array_spec(gfc_array_spec**, bool, bool) (array.c:802) ==1018== by 0x803396: variable_decl (decl.c:2520) ==1018== by 0x803396: gfc_match_data_decl() (decl.c:6200) ==1018== by 0x86F88D: match_word (parse.c:65) ==1018== by 0x86F88D: decode_statement() (parse.c:376) ==1018== by 0x874C14: next_free (parse.c:1315) ==1018== by 0x874C14: next_statement() (parse.c:1547) ==1018== by 0x876CC4: parse_derived (parse.c:3382) ==1018== by 0x876CC4: parse_spec(gfc_statement) (parse.c:3923) ==1018== by 0x87949C: parse_progunit(gfc_statement) (parse.c:5892) ==1018== by 0x87AB80: gfc_parse_file() (parse.c:6433) ==1018== by 0x8CC54F: gfc_be_parse_file() (f95-lang.c:212) ==1018== by 0xE4C123: compile_file() (toplev.c:458) ==1018== by 0x7D2D91: do_compile (toplev.c:2327) ==1018== by 0x7D2D91: toplev::main(int, char**) (toplev.c:2466) ==1018== by 0x7D6B5E: main (main.c:39)
The following patch fixes the invalid read: diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c index 5677d920239..783e4c7354b 100644 --- a/gcc/fortran/class.c +++ b/gcc/fortran/class.c @@ -2906,7 +2906,9 @@ gfc_find_vtab (gfc_typespec *ts) case BT_DERIVED: return gfc_find_derived_vtab (ts->u.derived); case BT_CLASS: - if (ts->u.derived->components && ts->u.derived->components->ts.u.derived) + if (ts->u.derived->attr.is_class + && ts->u.derived->components + && ts->u.derived->components->ts.u.derived) return gfc_find_derived_vtab (ts->u.derived->components->ts.u.derived); else return NULL; Not regtested yet.
Patch: https://gcc.gnu.org/pipermail/fortran/2021-January/055509.html
The master branch has been updated by Harald Anlauf <anlauf@gcc.gnu.org>: https://gcc.gnu.org/g:d816b0c144d15e6570eb5b124b9f3ccbe3d40082 commit r11-6405-gd816b0c144d15e6570eb5b124b9f3ccbe3d40082 Author: Harald Anlauf <anlauf@gmx.de> Date: Fri Jan 1 18:55:41 2021 +0100 PR fortran/96381 - invalid read in gfc_find_derived_vtab An invalid declaration of a CLASS instance can lead to an internal state with inconsistent attributes during parsing that needs to be handled with sufficient care when processing subsequent statements. Avoid a lookup of the vtab entry for such cases. gcc/fortran/ChangeLog: * class.c (gfc_find_vtab): Add check on attribute is_class.
*** Bug 98263 has been marked as a duplicate of this bug. ***
The releases/gcc-10 branch has been updated by Harald Anlauf <anlauf@gcc.gnu.org>: https://gcc.gnu.org/g:78ff090d0a0bb5a77560203b3b49bb7da7fcb88c commit r10-9200-g78ff090d0a0bb5a77560203b3b49bb7da7fcb88c Author: Harald Anlauf <anlauf@gmx.de> Date: Fri Jan 1 18:55:41 2021 +0100 PR fortran/96381 - invalid read in gfc_find_derived_vtab An invalid declaration of a CLASS instance can lead to an internal state with inconsistent attributes during parsing that needs to be handled with sufficient care when processing subsequent statements. Avoid a lookup of the vtab entry for such cases. gcc/fortran/ChangeLog: * class.c (gfc_find_vtab): Add check on attribute is_class. (cherry picked from commit d816b0c144d15e6570eb5b124b9f3ccbe3d40082)
The releases/gcc-9 branch has been updated by Harald Anlauf <anlauf@gcc.gnu.org>: https://gcc.gnu.org/g:2bfcf6011a6cdce0439e3d1b94bcb5fcf078f4c2 commit r9-9151-g2bfcf6011a6cdce0439e3d1b94bcb5fcf078f4c2 Author: Harald Anlauf <anlauf@gmx.de> Date: Fri Jan 1 18:55:41 2021 +0100 PR fortran/96381 - invalid read in gfc_find_derived_vtab An invalid declaration of a CLASS instance can lead to an internal state with inconsistent attributes during parsing that needs to be handled with sufficient care when processing subsequent statements. Avoid a lookup of the vtab entry for such cases. gcc/fortran/ChangeLog: * class.c (gfc_find_vtab): Add check on attribute is_class. (cherry picked from commit d816b0c144d15e6570eb5b124b9f3ccbe3d40082)
Fixed on all branches where testcase gfortran.dg/pr93337.f90 was committed. Thanks for the report!