// 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.

#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MUTAGEN_H_
#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MUTAGEN_H_

#include <stddef.h>

#include <random>

#include "src/lib/fxl/macros.h"
#include "src/sys/fuzzing/common/input.h"
#include "src/sys/fuzzing/common/options.h"
#include "src/sys/fuzzing/realmfuzzer/engine/dictionary.h"

namespace fuzzing {

// Describes the types of mutation corresponding to the |Mutagen| methods below, and is used to
// record the sequence of mutations.
//
// The order here matters, as |Mutagen::Mutate| violates the abstraction a bit to get better
// performance: it uses the ordering to constrain which mutations to pick from based on the input
// size and output capacity.
//
// TODO(fxbug.dev/84365): This is currently missing a strategy to pull from the dictionary.
// TODO(fxbug.dev/85308): Add support for data-flow-guided fuzzing.
enum Mutation : uint8_t {
  // 1 < size
  kSkipSome,

  // 1 < size <= capacity
  kShuffle,
  kReplaceSome,

  // 0 < size <= capacity
  kFlip,
  kReplaceOne,
  kReplaceUnsigned,
  kReplaceNum,
  kMergeReplace,

  // 0 < size < capacity
  kInsertSome,
  kMergeInsert,

  // 0 <= size < capacity
  kInsertOne,
  kInsertRepeated,
};

// This class represents the source of mutations when fuzzing. It is heavily inspired by libFuzzer's
// MutationDispatcher, here:
//   https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/fuzzer/FuzzerMutate.cpp
//
// During fuzzing, the runner will pick an input from the corpus, and pass it to this object. It
// will then use this object to generate a sequence of mutated inputs that it can send to the
// target adapter.
class Mutagen final {
 public:
  Mutagen() = default;
  ~Mutagen() = default;

  const Dictionary& dictionary() const { return dictionary_; }

  // Callers can write data into the returned inputs.
  Input* base_input() { return &base_input_; }
  Input* crossover() { return &crossover_; }

  // The sequence of mutations since the input was last set.
  const std::vector<Mutation>& mutations() const { return mutations_; }

  void set_dictionary(Dictionary dictionary) { dictionary_ = std::move(dictionary); }

  void reset_mutations() { mutations_.clear(); }

  // Adds default values to unspecified options that are needed by objects of this class.
  static void AddDefaults(Options* options);

  // Sets options.
  void Configure(const OptionsPtr& options);

  // Makes a copy of the previously configured input, mutates it using a pseudoradomly selected
  // mutation strategy, and stores the result in |out|.
  void Mutate(Input* out);

  // All other the mutators below return true when they have successfully mutated and written |data|
  // to |out|, and false otherwise. Each makes assumptions about the given |size|, which are
  // enforced by |Mutate|, above. Callers should not call these directly except for testing. Use
  // |Mutate| instead.

  // Remove some bytes from |data| when writing to |out|. Assumes |size > 1|; |size > max_size| is
  // allowed.
  bool SkipSome(const uint8_t* data, size_t size, size_t max_size, Input* out);

  // Shuffle some subsequence of |data| when writing it to |out|. Assumes |size > 1|.
  bool Shuffle(const uint8_t* data, size_t size, Input* out);

  // Flip a bit at some location in |data| when writing it to |out|. Assumes |size != 0|.
  bool Flip(const uint8_t* data, size_t size, Input* out);

  // Replace one byte in |data| when writing it to |out|. Assumes |size != 0|.
  bool ReplaceOne(const uint8_t* data, size_t size, Input* out);

  // Find and replace an unsigned integer value in |data| when writing it to |out|. Assumes
  // |size != 0|.
  bool ReplaceUnsigned(const uint8_t* data, size_t size, Input* out);

  // Find and replace an ASCII representation of a number in |data| when writing it to |out|.
  // Assumes |size != 0|.
  bool ReplaceNum(const uint8_t* data, size_t size, Input* out);

  // Replace some subsequence of |data| with another, possibly overlapping subsequence when writing
  // it to |out|. Assumes |size != 0|.
  bool ReplaceSome(const uint8_t* data, size_t size, Input* out);

  // For each of |size1| bytes, choose from |data1| or |data2|, and write the result to |out|.
  bool MergeReplace(const uint8_t* data1, size_t size1, const uint8_t* data2, size_t size2,
                    Input* out);

  // Copy some section of |data| and insert it when writing |data| to |out|. Assumes
  // |size < max_size|.
  bool InsertSome(const uint8_t* data, size_t size, size_t max_size, Input* out);

  // Interleave segments of |data1| and |data2| and write the result to |out|, up to
  // |max_size|.
  bool MergeInsert(const uint8_t* data1, size_t size1, const uint8_t* data2, size_t size2,
                   size_t max_size, Input* out);

  // Insert one byte somewhere into |data| when writing it to |out|. Implies a "max_size" of
  // |size + 1|.
  bool InsertOne(const uint8_t* data, size_t size, Input* out);

  // Insert a sequence created by repeating a byte somewhere into |data| when writing it to |out|.
  // Assumes |size < max_size|.
  bool InsertRepeated(const uint8_t* data, size_t size, size_t max_size, Input* out);

 private:
  // Returns a random value.
  template <typename T>
  T Pick() {
    return static_cast<T>(prng_());
  }

  // Returns a random value in [min, max].
  template <typename T>
  T Pick(T min, T max) {
    return min + (Pick<T>() % (max - min + 1));
  }

  // Pick a random byte, with preference given to 0 and 255.
  uint8_t PickPreferred();

  // Pick a random byte, with preference given to special ASCII characters.
  char PickSpecial();

 private:
  OptionsPtr options_;
  std::minstd_rand prng_;
  Input base_input_;
  Input crossover_;
  Dictionary dictionary_;
  std::vector<Mutation> mutations_;

  FXL_DISALLOW_COPY_ASSIGN_AND_MOVE(Mutagen);
};

template <>
bool Mutagen::Pick<bool>();
template <>
uint64_t Mutagen::Pick<uint64_t>();

}  // namespace fuzzing

#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MUTAGEN_H_
