blob: 845aa2fa580d08e69679952ff754c75985f5b17f [file] [log] [blame] [edit]
/*
* Copyright 2021 WebAssembly Community Group participants
*
* 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
*
* http://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.
*/
#ifndef wasm_tools_fuzzing_random_h
#define wasm_tools_fuzzing_random_h
#include <cstdint>
#include <map>
#include <vector>
#include "wasm-features.h"
namespace wasm {
class Random {
// The input seed bytes.
std::vector<char> bytes;
// The current position in `bytes`.
size_t pos = 0;
// Whether we already cycled through all the input (which might mean we should
// try to finish things off).
bool finishedInput = false;
// After we finish the input, we start going through it again, but xoring
// so it's not identical.
int xorFactor = 0;
// Features used for picking among FeatureOptions.
FeatureSet features;
public:
Random(std::vector<char>&& bytes, FeatureSet features);
Random(std::vector<char>&& bytes)
: Random(std::move(bytes), FeatureSet::All) {}
// Methods for getting random data.
int8_t get();
int16_t get16();
int32_t get32();
int64_t get64();
float getFloat();
double getDouble();
// Choose an integer value in [0, x). This doesn't use a perfectly uniform
// distribution, but it's fast and reasonable.
uint32_t upTo(uint32_t x);
bool oneIn(uint32_t x) { return upTo(x) == 0; }
// Apply upTo twice, generating a skewed distribution towards
// low values.
uint32_t upToSquared(uint32_t x) { return upTo(upTo(x)); }
bool finished() { return finishedInput; }
// Pick from a vector-like container
template<typename T> const typename T::value_type& pick(const T& vec) {
assert(!vec.empty());
auto index = upTo(vec.size());
return vec[index];
}
// Pick from a fixed list
template<typename T, typename... Args> T pick(T first, Args... args) {
auto num = sizeof...(Args) + 1;
auto temp = upTo(num);
return pickGivenNum<T>(temp, first, args...);
}
template<typename T> T pickGivenNum(size_t num, T first) {
assert(num == 0);
return first;
}
// Trick to avoid a bug in GCC 7.x.
// Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82800
#define GCC_VERSION \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if GCC_VERSION > 70000 && GCC_VERSION < 70300
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template<typename T, typename... Args>
T pickGivenNum(size_t num, T first, Args... args) {
if (num == 0) {
return first;
}
return pickGivenNum<T>(num - 1, args...);
}
#if GCC_VERSION > 70000 && GCC_VERSION < 70300
#pragma GCC diagnostic pop
#endif
template<typename T> struct FeatureOptions {
template<typename... Ts>
FeatureOptions<T>& add(FeatureSet feature, T option, Ts... rest) {
options[feature].push_back(option);
return add(feature, rest...);
}
struct WeightedOption {
T option;
size_t weight;
};
template<typename... Ts>
FeatureOptions<T>&
add(FeatureSet feature, WeightedOption weightedOption, Ts... rest) {
for (size_t i = 0; i < weightedOption.weight; i++) {
options[feature].push_back(weightedOption.option);
}
return add(feature, rest...);
}
FeatureOptions<T>& add(FeatureSet feature) { return *this; }
std::map<FeatureSet, std::vector<T>> options;
};
template<typename T> std::vector<T> items(FeatureOptions<T>& picker) {
std::vector<T> matches;
for (const auto& item : picker.options) {
if (features.has(item.first)) {
matches.reserve(matches.size() + item.second.size());
matches.insert(matches.end(), item.second.begin(), item.second.end());
}
}
return matches;
}
template<typename T> const T pick(FeatureOptions<T>& picker) {
return pick(items(picker));
}
};
} // namespace wasm
#endif // wasm_tools_fuzzing_random_h