blob: 6b131de8aabec67c9939093eb496d138f7ddfddf [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include <limits>
#include <string>
#include <unordered_map>
#include <vector>
#include "src/lib/fxl/macros.h"
#include "src/sys/fuzzing/common/input.h"
#include "src/sys/fuzzing/common/options.h"
namespace fuzzing {
// This class represents a dictionary of input language keywords or other byte sequences that may be
// included in generating test inputs that are likely to uncover new features in a target, e.g.
// "GET" or "POST" for a fuzzer that takes HTTP inputs. The file format is the same as that of AFL,
// although it is best described by libFuzzer:
class Dictionary final {
using Word = std::vector<uint8_t>;
using Level = std::vector<Word>;
Dictionary() = default;
Dictionary(Dictionary&& other) noexcept { *this = std::move(other); }
~Dictionary() = default;
Dictionary& operator=(Dictionary&& other) noexcept;
// Sets options.
void Configure(const OptionsPtr& options);
// Adds |size| bytes as a word to this dictionary.
void Add(const void* data, size_t size, uint16_t level = 0);
// Adds a |word| to the dictionary.
void Add(Word&& word, uint16_t level = 0);
// Resets the dictionary to an initial state and attempts to interpret the given input as a
// dictionary. Invalid entries are skipped.
bool Parse(const Input& input);
// Writes the dictionary out to an input.
Input AsInput() const;
// Apply |func| to each word in the dictionary with a level at or below the previously
// |Configure|d dictionary level (default is 0).
void ForEachWord(fit::function<void(const uint8_t*, size_t)> func) const;
// Parses |str| as a dictionary level, which is an unsigned number. Returns false if |str| is not
// a valid number. Otherwise returns true and the parsed level via |out_level|.
bool ParseLevel(const std::string& str, uint16_t* out_level);
// Parse |str| as a word, which may contain sequences like \\, \", or \xNN where N is a hex digit.
// Returns false if the value is empty or contains invalid escape sequences (e.g. \x5G).
// Otherwise, returns true, the parsed word via |out_word|, and the portion of |str| that was not
// parsed in |out_remaining|.
bool ParseWord(const std::string& str, Word* out_word, std::string* out_remaining);
// Parses |str| as a number with the given |base|, e.g. 10 or 16. Returns false if |str| is not a
// number of if it cannot be expressed as a value of type |T|. Otherwise, returns true and the
// parsed value via |out|.
template <typename T>
bool ParseNumber(const std::string& str, int base, T* out) {
const char* c_str = str.c_str();
char* endptr;
auto u64 = std::strtoul(c_str, &endptr, 10);
if (c_str == endptr || *endptr != '\0' || u64 > std::numeric_limits<T>::max()) {
return false;
*out = static_cast<T>(u64);
return true;
OptionsPtr options_;
std::unordered_map<uint16_t, Level> words_by_level_;
uint16_t max_level_ = 0;
} // namespace fuzzing