aboutsummaryrefslogtreecommitdiff
path: root/gcc/diagnostic-format-sarif.cc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2023-03-24 20:52:34 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2023-03-24 20:52:34 -0400
commitd495ea2b232f3eb50155d7c7362c09a744766746 (patch)
tree0216e5a6060e9e3762d6951bc47524cea7e9c7f3 /gcc/diagnostic-format-sarif.cc
parent13ec81eb4c3b484ad636000fa8f6d925e15fb983 (diff)
downloadgcc-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.cc78
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);