|  | // Copyright 2020 The Pigweed Authors | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); you may not | 
|  | // use this file except in compliance with the License. You may obtain a copy of | 
|  | // the License at | 
|  | // | 
|  | //     https://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
|  | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 
|  | // License for the specific language governing permissions and limitations under | 
|  | // the License. | 
|  |  | 
|  | // This file implements a basic fuzz test for the Detokenizer. | 
|  | // An instance of the Detokenizer is created from a minimal, nearly-empty token | 
|  | // database. Fuzz data is fed to the detokenizer in various supported input | 
|  | // argument formats at random, when then decodes this data and tries to match | 
|  | // it to tokens in the database. | 
|  |  | 
|  | #include <cstddef> | 
|  | #include <cstdint> | 
|  | #include <cstring> | 
|  | #include <vector> | 
|  |  | 
|  | #include "pw_fuzzer/fuzzed_data_provider.h" | 
|  | #include "pw_preprocessor/util.h" | 
|  | #include "pw_tokenizer/detokenize.h" | 
|  |  | 
|  | namespace pw::tokenizer { | 
|  | namespace { | 
|  |  | 
|  | constexpr size_t kFuzzRangeMin = 0; | 
|  | constexpr size_t kFuzzRangeMax = 10000; | 
|  |  | 
|  | enum DetokenizeBufferArgumentType : uint8_t { | 
|  | kSpan = 0, | 
|  | kStringView, | 
|  | kPtrAndLength, | 
|  | kMaxValue = kPtrAndLength | 
|  | }; | 
|  |  | 
|  | // In order to better fuzz the detokenizer, rather than use an empty token | 
|  | // database, we construct a minimal database with 4 entries out of a string | 
|  | // literal array that matches the token database format (see token_database.h | 
|  | // for detailed info on the database entry format) | 
|  | alignas(TokenDatabase::RawEntry) constexpr char kBasicData[] = | 
|  | "TOKENS\0\0" | 
|  | "\x04\x00\x00\x00" | 
|  | "\0\0\0\0" | 
|  | "\x01\x00\x00\x00----" | 
|  | "\x05\x00\x00\x00----" | 
|  | "\xFF\x00\x00\x00----" | 
|  | "\xFF\xEE\xEE\xDD----" | 
|  | "One\0" | 
|  | "TWO\0" | 
|  | "333\0" | 
|  | "FOUR"; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { | 
|  | static Detokenizer detokenizer(TokenDatabase::Create<kBasicData>()); | 
|  |  | 
|  | FuzzedDataProvider provider(data, size); | 
|  |  | 
|  | while (provider.remaining_bytes() != 0) { | 
|  | // Map the first word of the remaining fuzz data to a buffer argument | 
|  | // type, and feed the Detokenizer with a random length buffer to be | 
|  | // detokenized in the relevant format. The detokenized string returned | 
|  | // is itself of little consequence to this test. | 
|  | switch (provider.ConsumeEnum<DetokenizeBufferArgumentType>()) { | 
|  | case kSpan: { | 
|  | size_t consumed_size = provider.ConsumeIntegralInRange<size_t>( | 
|  | kFuzzRangeMin, kFuzzRangeMax); | 
|  | std::vector<uint8_t> buffer = | 
|  | provider.ConsumeBytes<uint8_t>(consumed_size); | 
|  | auto detokenized_string = | 
|  | detokenizer.Detokenize(std::span(&buffer[0], buffer.size())); | 
|  | static_cast<void>(detokenized_string); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case kStringView: { | 
|  | std::string str = | 
|  | provider.ConsumeRandomLengthString(provider.remaining_bytes()); | 
|  | auto detokenized_string = detokenizer.Detokenize(str); | 
|  | static_cast<void>(detokenized_string); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case kPtrAndLength: { | 
|  | size_t consumed_size = provider.ConsumeIntegralInRange<size_t>( | 
|  | kFuzzRangeMin, kFuzzRangeMax); | 
|  | std::vector<uint8_t> buffer = | 
|  | provider.ConsumeBytes<uint8_t>(consumed_size); | 
|  | auto detokenized_string = | 
|  | detokenizer.Detokenize(&buffer[0], buffer.size()); | 
|  | static_cast<void>(detokenized_string); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | }  // namespace pw::tokenizer |