diff options
author | David Malcolm <dmalcolm@redhat.com> | 2023-03-24 20:52:34 -0400 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2023-03-24 20:52:34 -0400 |
commit | d495ea2b232f3eb50155d7c7362c09a744766746 (patch) | |
tree | 0216e5a6060e9e3762d6951bc47524cea7e9c7f3 /gcc/diagnostic-format-sarif.cc | |
parent | 13ec81eb4c3b484ad636000fa8f6d925e15fb983 (diff) | |
download | gcc-d495ea2b232f3eb50155d7c7362c09a744766746.zip gcc-d495ea2b232f3eb50155d7c7362c09a744766746.tar.gz gcc-d495ea2b232f3eb50155d7c7362c09a744766746.tar.bz2 |
diagnostics: ensure that .sarif files are UTF-8 encoded [PR109098]
PR analyzer/109098 notes that the SARIF spec mandates that .sarif
files are UTF-8 encoded, but -fdiagnostics-format=sarif-file naively
assumes that the source files are UTF-8 encoded when quoting source
artefacts in the .sarif output, which can lead to us writing out
.sarif files with non-UTF-8 bytes in them (which break my reporting
scripts).
The root cause is that sarif_builder::maybe_make_artifact_content_object
was using maybe_read_file to load the file content as bytes, and
assuming they were UTF-8 encoded.
This patch reworks both overloads of this function (one used for the
whole file, the other for snippets of quoted lines) so that they go
through input.cc's file cache, which attempts to decode the input files
according to the input charset, and then encode as UTF-8. They also
check that the result actually is UTF-8, for cases where the input
charset is missing, or incorrectly specified, and omit the quoted
source for such awkward cases.
Doing so fixes all of the cases I've encountered.
The patch adds a new:
{ dg-final { verify-sarif-file } }
directive to all SARIF test cases in the test suite, which verifies
that the output is UTF-8 encoded, and is valid JSON. In particular
it verifies that when we complain about encoding problems, the .sarif
report we emit is itself correctly encoded.
gcc/ChangeLog:
PR analyzer/109098
* diagnostic-format-sarif.cc (read_until_eof): Delete.
(maybe_read_file): Delete.
(sarif_builder::maybe_make_artifact_content_object): Use
get_source_file_content rather than maybe_read_file.
Reject it if it's not valid UTF-8.
* input.cc (file_cache_slot::get_full_file_content): New.
(get_source_file_content): New.
(selftest::check_cpp_valid_utf8_p): New.
(selftest::test_cpp_valid_utf8_p): New.
(selftest::input_cc_tests): Call selftest::test_cpp_valid_utf8_p.
* input.h (get_source_file_content): New prototype.
gcc/testsuite/ChangeLog:
PR analyzer/109098
* c-c++-common/diagnostic-format-sarif-file-1.c: Add
verify-sarif-file directive.
* c-c++-common/diagnostic-format-sarif-file-2.c: Likewise.
* c-c++-common/diagnostic-format-sarif-file-3.c: Likewise.
* c-c++-common/diagnostic-format-sarif-file-4.c: Likewise.
* c-c++-common/diagnostic-format-sarif-file-Wbidi-chars.c: New
test case, adapted from Wbidi-chars-1.c.
* c-c++-common/diagnostic-format-sarif-file-bad-utf8-pr109098-1.c:
New test case.
* c-c++-common/diagnostic-format-sarif-file-bad-utf8-pr109098-2.c:
New test case.
* c-c++-common/diagnostic-format-sarif-file-bad-utf8-pr109098-3.c:
New test case, adapted from cpp/Winvalid-utf8-1.c.
* c-c++-common/diagnostic-format-sarif-file-valid-CP850.c: New
test case, adapted from gcc.dg/diagnostic-input-charset-1.c.
* gcc.dg/plugin/crash-test-ice-sarif.c: Add verify-sarif-file
directive.
* gcc.dg/plugin/crash-test-write-though-null-sarif.c: Likewise.
* gcc.dg/plugin/diagnostic-test-paths-5.c: Likewise.
* lib/scansarif.exp (verify-sarif-file): New procedure.
* lib/verify-sarif-file.py: New support script.
libcpp/ChangeLog:
PR analyzer/109098
* charset.cc (cpp_valid_utf8_p): New function.
* include/cpplib.h (cpp_valid_utf8_p): New prototype.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc/diagnostic-format-sarif.cc')
-rw-r--r-- | gcc/diagnostic-format-sarif.cc | 78 |
1 files changed, 17 insertions, 61 deletions
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index 2c48cbd..fd29ac2 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -1390,76 +1390,25 @@ sarif_builder::make_artifact_object (const char *filename) return artifact_obj; } -/* Read all data from F_IN until EOF. - Return a NULL-terminated buffer containing the data, which must be - freed by the caller. - Return NULL on errors. */ - -static char * -read_until_eof (FILE *f_in) -{ - /* Read content, allocating a buffer for it. */ - char *result = NULL; - size_t total_sz = 0; - size_t alloc_sz = 0; - char buf[4096]; - size_t iter_sz_in; - - while ( (iter_sz_in = fread (buf, 1, sizeof (buf), f_in)) ) - { - gcc_assert (alloc_sz >= total_sz); - size_t old_total_sz = total_sz; - total_sz += iter_sz_in; - /* Allow 1 extra byte for 0-termination. */ - if (alloc_sz < (total_sz + 1)) - { - size_t new_alloc_sz = alloc_sz ? alloc_sz * 2: total_sz + 1; - result = (char *)xrealloc (result, new_alloc_sz); - alloc_sz = new_alloc_sz; - } - memcpy (result + old_total_sz, buf, iter_sz_in); - } - - if (!feof (f_in)) - return NULL; - - /* 0-terminate the buffer. */ - gcc_assert (total_sz < alloc_sz); - result[total_sz] = '\0'; - - return result; -} - -/* Read all data from FILENAME until EOF. - Return a NULL-terminated buffer containing the data, which must be - freed by the caller. - Return NULL on errors. */ - -static char * -maybe_read_file (const char *filename) -{ - FILE *f_in = fopen (filename, "r"); - if (!f_in) - return NULL; - char *result = read_until_eof (f_in); - fclose (f_in); - return result; -} - /* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the full contents of FILENAME. */ json::object * sarif_builder::maybe_make_artifact_content_object (const char *filename) const { - char *text_utf8 = maybe_read_file (filename); - if (!text_utf8) + /* Let input.cc handle any charset conversion. */ + char_span utf8_content = get_source_file_content (filename); + if (!utf8_content) return NULL; - json::object *artifact_content_obj = new json::object (); - artifact_content_obj->set ("text", new json::string (text_utf8)); - free (text_utf8); + /* Don't add it if it's not valid UTF-8. */ + if (!cpp_valid_utf8_p(utf8_content.get_buffer (), utf8_content.length ())) + return NULL; + json::object *artifact_content_obj = new json::object (); + artifact_content_obj->set ("text", + new json::string (utf8_content.get_buffer (), + utf8_content.length ())); return artifact_content_obj; } @@ -1501,6 +1450,13 @@ sarif_builder::maybe_make_artifact_content_object (const char *filename, if (!text_utf8) return NULL; + /* Don't add it if it's not valid UTF-8. */ + if (!cpp_valid_utf8_p(text_utf8, strlen(text_utf8))) + { + free (text_utf8); + return NULL; + } + json::object *artifact_content_obj = new json::object (); artifact_content_obj->set ("text", new json::string (text_utf8)); free (text_utf8); |