From 85001c55fb678415922960171b27e4bd4cfa4ef5 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Sat, 19 Dec 2020 10:42:27 -0500 Subject: [PATCH] Fixing UTF-8 validation under PPC64 (#1346) * Entering a new UTF-8 test * Maybe *I* had a bug in the tests. * Replacing nulls with 1s. * Let us try to be more verbose. * Return 0. * Fixing issue. * Adding puzzler scenario. * Fixing PPC64 Co-authored-by: Daniel Lemire --- fuzz/fuzz_utf8.cpp | 20 ++++++++++++++++ include/simdjson/ppc64/simd.h | 2 +- src/ppc64/dom_parser_implementation.cpp | 3 ++- tests/unicode_tests.cpp | 31 ++++++++++++++++++++++--- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/fuzz/fuzz_utf8.cpp b/fuzz/fuzz_utf8.cpp index aceff2503..397b39a1c 100644 --- a/fuzz/fuzz_utf8.cpp +++ b/fuzz/fuzz_utf8.cpp @@ -12,6 +12,24 @@ #include #include "supported_implementations.h" +extern "C" int VerboseTestOneInput(const uint8_t *Data, size_t Size) { + static const auto supported_implementations=get_runtime_supported_implementations(); + for(size_t i = 0; i <= Size; i++) { + std::cout<<"size: "<supported_by_runtime_system()) { continue; } + const bool current=e->validate_utf8((const char*)Data,i); + std::cout<name()<<" returns "< struct simd8 : base8_numeric { template struct simd8x64 { static constexpr int NUM_CHUNKS = 64 / sizeof(simd8); static_assert(NUM_CHUNKS == 4, - "Westmere kernel should use four registers per 64-byte block."); + "PPC64 kernel should use four registers per 64-byte block."); const simd8 chunks[NUM_CHUNKS]; simd8x64(const simd8x64 &o) = delete; // no copy allowed diff --git a/src/ppc64/dom_parser_implementation.cpp b/src/ppc64/dom_parser_implementation.cpp index d494ca996..b61187272 100644 --- a/src/ppc64/dom_parser_implementation.cpp +++ b/src/ppc64/dom_parser_implementation.cpp @@ -49,7 +49,8 @@ simdjson_really_inline json_character_block json_character_block::classify(const } simdjson_really_inline bool is_ascii(const simd8x64& input) { - return input.reduce_or().saturating_sub(0b10000000u).bits_not_set_anywhere(); + // careful: 0x80 is not ascii. + return input.reduce_or().saturating_sub(0b01111111u).bits_not_set_anywhere(); } simdjson_unused simdjson_really_inline simd8 must_be_continuation(const simd8 prev1, const simd8 prev2, const simd8 prev3) { diff --git a/tests/unicode_tests.cpp b/tests/unicode_tests.cpp index 093e1c809..065f4ef9f 100644 --- a/tests/unicode_tests.cpp +++ b/tests/unicode_tests.cpp @@ -223,15 +223,17 @@ void test() { "\x80", "\x91\x85\x95\x9e", "\x6c\x02\x8e\x18", - "[[[[[[[[[[[[[[[\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}; - for (size_t i = 0; i < 8; i++) { + "\x25\x5b\x6e\x2c\x32\x2c\x5b\x5b\x33\x2c\x34\x2c\x05\x29\x2c\x33\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5d\x2c\x35\x2e\x33\x2c\x39\x2e\x33\x2c\x37\x2e\x33\x2c\x39\x2e\x34\x2c\x37\x2e\x33\x2c\x39\x2e\x33\x2c\x37\x2e\x33\x2c\x39\x2e\x34\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x20\x01\x01\x01\x01\x01\x02\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x23\x0a\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x7e\x7e\x0a\x0a\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5d\x2c\x37\x2e\x33\x2c\x39\x2e\x33\x2c\x37\x2e\x33\x2c\x39\x2e\x34\x2c\x37\x2e\x33\x2c\x39\x2e\x33\x2c\x37\x2e\x33\x2c\x39\x2e\x34\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x5d\x01\x01\x80\x01\x01\x01\x79\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01", + "[[[[[[[[[[[[[[[\x80\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x010\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01", + "\x20\x0b\x01\x01\x01\x64\x3a\x64\x3a\x64\x3a\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x5b\x30\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x80\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"}; + for (size_t i = 0; i < sizeof(goodsequences)/sizeof(goodsequences[0]); i++) { size_t len = std::strlen(goodsequences[i]); if (!simdjson::validate_utf8(goodsequences[i], len)) { printf("bug goodsequences[%zu]\n", i); abort(); } } - for (size_t i = 0; i < 26; i++) { + for (size_t i = 0; i < sizeof(badsequences)/sizeof(badsequences[0]); i++) { size_t len = std::strlen(badsequences[i]); if (simdjson::validate_utf8(badsequences[i], len)) { printf("bug lookup2 badsequences[%zu]\n", i); @@ -240,7 +242,30 @@ void test() { } printf("tests ok.\n"); } + +// This is an attempt at reproducing an issue with the utf8 fuzzer +void puzzler() { + std::cout << "running puzzler... " << std::endl; + const char* bad64 = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + size_t length = 64; + std::cout << "Input: \""; + for(size_t j = 0; j < length; j++) { + std::cout << "\\x" << std::hex << std::setw(2) << std::setfill('0') << uint32_t(bad64[j]); + } + std::cout << "\"" << std::endl; + bool is_ok{true}; + for(const auto& e: simdjson::available_implementations) { + if(!e->supported_by_runtime_system()) { continue; } + const bool current = e->validate_utf8(bad64, length); + std::cout << e->name() << " returns " << current << std::endl; + if(current) { is_ok = false; } + } + if(!is_ok) { abort(); } + std::cout << "Ok!" << std::endl; +} + int main() { + puzzler(); brute_force_tests(); test(); return EXIT_SUCCESS;