aboutsummaryrefslogtreecommitdiff
path: root/libcpp
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 /libcpp
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 'libcpp')
-rw-r--r--libcpp/charset.cc27
-rw-r--r--libcpp/include/cpplib.h1
2 files changed, 28 insertions, 0 deletions
diff --git a/libcpp/charset.cc b/libcpp/charset.cc
index 3c47d4f..d7f323b 100644
--- a/libcpp/charset.cc
+++ b/libcpp/charset.cc
@@ -1864,6 +1864,33 @@ _cpp_valid_utf8 (cpp_reader *pfile,
return true;
}
+/* Return true iff BUFFER of size NUM_BYTES is validly-encoded UTF-8. */
+
+extern bool
+cpp_valid_utf8_p (const char *buffer, size_t num_bytes)
+{
+ const uchar *iter = (const uchar *)buffer;
+ size_t bytesleft = num_bytes;
+ while (bytesleft > 0)
+ {
+ /* one_utf8_to_cppchar implements 5-byte and 6 byte sequences as per
+ RFC 2279, but this has been superceded by RFC 3629, which
+ restricts UTF-8 to 1-byte through 4-byte sequences, and
+ states "the octet values C0, C1, F5 to FF never appear".
+
+ Reject such values. */
+ if (*iter >= 0xf4)
+ return false;
+
+ cppchar_t cp;
+ int err = one_utf8_to_cppchar (&iter, &bytesleft, &cp);
+ if (err)
+ return false;
+ }
+ /* No problems encountered. */
+ return true;
+}
+
/* Subroutine of convert_hex and convert_oct. N is the representation
in the execution character set of a numeric escape; write it into the
string buffer TBUF and update the end-of-string pointer therein. WIDE
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 8df071e..a6f0abd 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -1600,5 +1600,6 @@ int cpp_wcwidth (cppchar_t c);
bool cpp_input_conversion_is_trivial (const char *input_charset);
int cpp_check_utf8_bom (const char *data, size_t data_length);
+bool cpp_valid_utf8_p (const char *data, size_t num_bytes);
#endif /* ! LIBCPP_CPPLIB_H */