//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef TEST_LIBCXX_FUZZING_FUZZ_H #define TEST_LIBCXX_FUZZING_FUZZ_H #include #include #include #include // std::strlen #include #include #include // std::swap // This is a struct we can use to test the stable_XXX algorithms. // Perform the operation on the key, then check the order of the payload. struct ByteWithPayload { std::uint8_t key; std::size_t payload; ByteWithPayload(std::uint8_t k) : key(k), payload(0) { } ByteWithPayload(std::uint8_t k, std::size_t p) : key(k), payload(p) { } friend bool operator==(ByteWithPayload const& x, ByteWithPayload const& y) { return x.key == y.key && x.payload == y.payload; } friend bool operator!=(ByteWithPayload const& x, ByteWithPayload const& y) { return !(x == y); } struct key_less { bool operator()(ByteWithPayload const& x, ByteWithPayload const& y) const { return x.key < y.key; } }; struct payload_less { bool operator()(ByteWithPayload const& x, ByteWithPayload const& y) const { return x.payload < y.payload; } }; struct total_less { bool operator()(ByteWithPayload const& x, ByteWithPayload const& y) const { return x.key == y.key ? x.payload < y.payload : x.key < y.key; } }; friend void swap(ByteWithPayload& lhs, ByteWithPayload& rhs) { std::swap(lhs.key, rhs.key); std::swap(lhs.payload, rhs.payload); } }; // Faster version of std::is_permutation // // Builds a set of buckets for each of the key values, and sums all the payloads. // Not 100% perfect, but _way_ faster. template ::value_type, ByteWithPayload>::value && std::is_same::value_type, ByteWithPayload>::value >::type> bool fast_is_permutation(Iter1 first1, Iter1 last1, Iter2 first2) { std::size_t xBuckets[256] = {0}; std::size_t xPayloads[256] = {0}; std::size_t yBuckets[256] = {0}; std::size_t yPayloads[256] = {0}; for (; first1 != last1; ++first1, ++first2) { xBuckets[first1->key]++; xPayloads[first1->key] += first1->payload; yBuckets[first2->key]++; yPayloads[first2->key] += first2->payload; } for (std::size_t i = 0; i < 256; ++i) { if (xBuckets[i] != yBuckets[i]) return false; if (xPayloads[i] != yPayloads[i]) return false; } return true; } template ::value_type, std::uint8_t>::value && std::is_same::value_type, std::uint8_t>::value >::type> bool fast_is_permutation(Iter1 first1, Iter1 last1, Iter2 first2) { std::size_t xBuckets[256] = {0}; std::size_t yBuckets[256] = {0}; for (; first1 != last1; ++first1, ++first2) { xBuckets[*first1]++; yBuckets[*first2]++; } for (std::size_t i = 0; i < 256; ++i) if (xBuckets[i] != yBuckets[i]) return false; return true; } // When running inside OSS-Fuzz, we link against a fuzzing library that defines // main() and calls LLVMFuzzerTestOneInput. // // Otherwise, when e.g. running the Lit tests, we define main() to run fuzzing // tests on a few inputs. #if !defined(LIBCPP_OSS_FUZZ) extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t*, std::size_t); int main(int, char**) { const char* test_cases[] = { "", "s", "bac", "bacasf", "lkajseravea", "adsfkajdsfjkas;lnc441324513,34535r34525234", "b*c", "ba?sf", "lka*ea", "adsf*kas;lnc441[0-9]1r34525234" }; for (const char* tc : test_cases) { const std::size_t size = std::strlen(tc); const std::uint8_t* data = reinterpret_cast(tc); int result = LLVMFuzzerTestOneInput(data, size); assert(result == 0); } return 0; } #endif // !LIBCPP_OSS_FUZZ #endif // TEST_LIBCXX_FUZZING_FUZZ_H