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 /libcpp/charset.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 'libcpp/charset.cc')
-rw-r--r-- | libcpp/charset.cc | 27 |
1 files changed, 27 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 |