Bug 105916 - gfortran -fdiagnostics-format=json/sarif* output contains buffered errors
Summary: gfortran -fdiagnostics-format=json/sarif* output contains buffered errors
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 12.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2022-06-10 11:55 UTC by gnikit
Modified: 2022-06-16 13:25 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-06-12 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description gnikit 2022-06-10 11:55:57 UTC
Using the option `-fdiagnostics-format=json` with gfortran yields unexpected and erroneous output.

Consider the trivial MWE

tmp.f90
```fortran
program main
    implicit none
    print*, "Hello World!"
end program main
```

One would expect when compiled the json output to be empty, but 

gfortran -fdiagnostics-format=json tmp.f90


results to (formatted to be human readable)

```json
[
  {
    "kind": "error",
    "column-origin": 1,
    "children": [
      {
        "kind": "error",
        "escape-source": false,
        "locations": [
          {
            "caret": {
              "byte-column": 13,
              "display-column": 13,
              "line": 2,
              "file": "tmp.f90",
              "column": 13
            }
          }
        ],
        "message": "Function ‘implicit’ requires an argument list at (1)"
      },
      {
        "kind": "error",
        "escape-source": false,
        "locations": [
          {
            "caret": {
              "byte-column": 13,
              "display-column": 13,
              "line": 2,
              "file": "tmp.f90",
              "column": 13
            }
          }
        ],
        "message": "Syntax error in IMPLICIT statement at (1)"
      },
      {
        "kind": "error",
        "escape-source": false,
        "locations": [
          {
            "caret": {
              "byte-column": 10,
              "display-column": 10,
              "line": 3,
              "file": "tmp.f90",
              "column": 10
            }
          }
        ],
        "message": "Function ‘print’ requires an argument list at (1)"
      },
      {
        "kind": "error",
        "escape-source": false,
        "locations": [
          {
            "caret": {
              "byte-column": 4,
              "display-column": 4,
              "line": 4,
              "file": "tmp.f90",
              "column": 4
            }
          }
        ],
        "message": "Function ‘end’ requires an argument list at (1)"
      }
    ],
    "escape-source": false,
    "locations": [
      {
        "caret": {
          "byte-column": 8,
          "display-column": 8,
          "line": 1,
          "file": "tmp.f90",
          "column": 8
        }
      }
    ],
    "message": "Function ‘program’ requires an argument list at (1)"
  }
]

```
Comment 1 David Malcolm 2022-06-12 16:09:47 UTC
Thanks for filing this.

Reproducable with trunk.  On trunk I also see similar behavior with the new SARIF output format via options:
  -fdiagnostics-format=sarif-stderr
  -fdiagnostics-format=sarif-file
and with:
  -fdiagnostics-format=json-file

With json output, the json::object for the error is being stashed for later output here:

(gdb) bt
#0  json_end_diagnostic (context=0x3f4a370, diagnostic=0x3f46100, orig_diag_kind=DK_UNSPECIFIED) at ../../src/gcc/diagnostic-format-json.cc:159
#1  0x0000000002e78ecf in diagnostic_report_diagnostic (context=0x3f31b00 <global_diagnostic_context>, diagnostic=0x7fffffffd170)
    at ../../src/gcc/diagnostic.cc:1548
#2  0x0000000000adaca8 in gfc_report_diagnostic (diagnostic=0x7fffffffd170) at ../../src/gcc/fortran/error.cc:883
#3  0x0000000000adc61d in gfc_error_opt(int, const char *, typedef __va_list_tag __va_list_tag *) (opt=0, 
    gmsgid=0x2f7b0d0 "Function %qs requires an argument list at %C", ap=0x7fffffffd258) at ../../src/gcc/fortran/error.cc:1453
#4  0x0000000000adc7ce in gfc_error (gmsgid=0x2f7b0d0 "Function %qs requires an argument list at %C") at ../../src/gcc/fortran/error.cc:1482
#5  0x0000000000b83162 in gfc_match_rvalue (result=0x7fffffffd4b0) at ../../src/gcc/fortran/primary.cc:3711
#6  0x0000000000b319f3 in match_primary (result=0x7fffffffd4b0) at ../../src/gcc/fortran/matchexp.cc:157
#7  0x0000000000b31b0e in match_level_1 (result=0x7fffffffd508) at ../../src/gcc/fortran/matchexp.cc:211
#8  0x0000000000b31bd8 in match_mult_operand (result=0x7fffffffd568) at ../../src/gcc/fortran/matchexp.cc:267
#9  0x0000000000b31df1 in match_add_operand (result=0x7fffffffd5b0) at ../../src/gcc/fortran/matchexp.cc:356
#10 0x0000000000b320bf in match_level_2 (result=0x7fffffffd608) at ../../src/gcc/fortran/matchexp.cc:480
#11 0x0000000000b32257 in match_level_3 (result=0x7fffffffd678) at ../../src/gcc/fortran/matchexp.cc:551
#12 0x0000000000b32361 in match_level_4 (result=0x7fffffffd6c8) at ../../src/gcc/fortran/matchexp.cc:599
#13 0x0000000000b32616 in match_and_operand (result=0x7fffffffd718) at ../../src/gcc/fortran/matchexp.cc:693
#14 0x0000000000b3269e in match_or_operand (result=0x7fffffffd768) at ../../src/gcc/fortran/matchexp.cc:722
#15 0x0000000000b327a8 in match_equiv_operand (result=0x7fffffffd7b8) at ../../src/gcc/fortran/matchexp.cc:765
#16 0x0000000000b328b2 in match_level_5 (result=0x7fffffffd810) at ../../src/gcc/fortran/matchexp.cc:811
#17 0x0000000000b32a01 in gfc_match_expr (result=0x7fffffffd9b0) at ../../src/gcc/fortran/matchexp.cc:870
#18 0x0000000000b24e0e in gfc_match (target=0x2f66b7a " %e") at ../../src/gcc/fortran/match.cc:1125
#19 0x0000000000b2e443 in gfc_match_ptr_fcn_assign () at ../../src/gcc/fortran/match.cc:6039
#20 0x0000000000b693e9 in match_word (str=0x0, subr=0xb2e2c3 <gfc_match_ptr_fcn_assign()>, old_locus=0x7fffffffdba0)
    at ../../src/gcc/fortran/parse.cc:67
#21 0x0000000000b6a0d8 in decode_statement () at ../../src/gcc/fortran/parse.cc:375
#22 0x0000000000b72035 in next_free () at ../../src/gcc/fortran/parse.cc:1397
#23 0x0000000000b72664 in next_statement () at ../../src/gcc/fortran/parse.cc:1629
#24 0x0000000000b7af20 in gfc_parse_file () at ../../src/gcc/fortran/parse.cc:6738
#25 0x0000000000be3143 in gfc_be_parse_file () at ../../src/gcc/fortran/f95-lang.cc:229
#26 0x0000000001523847 in compile_file () at ../../src/gcc/toplev.cc:452
#27 0x0000000001527367 in do_compile (no_backend=false) at ../../src/gcc/toplev.cc:2144
#28 0x00000000015277f9 in toplev::main (this=0x7fffffffde3a, argc=15, argv=0x7fffffffdf48) at ../../src/gcc/toplev.cc:2296
#29 0x0000000002e4ab76 in main (argc=15, argv=0x7fffffffdf48) at ../../src/gcc/main.cc:39
Comment 2 David Malcolm 2022-06-12 16:18:57 UTC
With the default diagnostic output format, for this error it looks like gfc_error_opt uses a "buffered_p" global; the message is written to a pp_error_buffer, rather than the diagnostic context's regular pretty printer.

The buffering is enabled here:

(gdb) bt
#0  gfc_buffer_error (flag=true) at ../../src/gcc/fortran/error.cc:120
#1  0x0000000000b725f7 in next_statement () at ../../src/gcc/fortran/parse.cc:1611
#2  0x0000000000b7af20 in gfc_parse_file () at ../../src/gcc/fortran/parse.cc:6738
#3  0x0000000000be3143 in gfc_be_parse_file () at ../../src/gcc/fortran/f95-lang.cc:229
#4  0x0000000001523847 in compile_file () at ../../src/gcc/toplev.cc:452
#5  0x0000000001527367 in do_compile (no_backend=false) at ../../src/gcc/toplev.cc:2144
#6  0x00000000015277f9 in toplev::main (this=0x7fffffffde6a, argc=14, argv=0x7fffffffdf78) at ../../src/gcc/toplev.cc:2296
#7  0x0000000002e4ab76 in main (argc=14, argv=0x7fffffffdf78) at ../../src/gcc/main.cc:39




#1  0x0000000000b725f7 in next_statement () at ../../src/gcc/fortran/parse.cc:1611
1611	      gfc_buffer_error (true);
(gdb) list
1606	  gfc_current_ns->old_equiv = gfc_current_ns->equiv;
1607	  gfc_current_ns->old_data = gfc_current_ns->data;
1608	  for (;;)
1609	    {
1610	      gfc_statement_label = NULL;
1611	      gfc_buffer_error (true);     <<<<<< BUFFERING ENABLED HERE
1612	
1613	      if (gfc_at_eol ())
1614		gfc_advance_line ();
1615	
1616	      gfc_skip_comments ();
1617	
1618	      if (gfc_at_end ())
1619		{
1620		  st = ST_NONE;
1621		  break;
1622		}
1623	
1624	      if (gfc_define_undef_line ())
1625		continue;
1626	
1627	      old_locus = gfc_current_locus;
1628	
1629	      st = (gfc_current_form == FORM_FIXED) ? next_fixed () : next_free ();
1630	
1631	      if (st != ST_NONE)
1632		break;
1633	    }
1634	
1635	  gfc_buffer_error (false);   <<<<<< BUFFERING DISABLED HERE


The output handling for json/sarif doesn't know about this fortran-specific buffered_p thing, hence these buffered errors get erroneously added to the JSON/SARIF output.