#include "ir/branch-utils.h"
#include "ir/memory-utils.h"
#include "ir/struct-utils.h"
#include "support/insert_ordered.h"
#include "tools/fuzzing/random.h"
#include <ir/eh-utils.h>
#include <ir/find_all.h>
#include <ir/literal-utils.h>
#include <ir/manipulation.h>
#include <ir/names.h>
#include <ir/utils.h>
#include <support/file.h>
#include <tools/optimization-options.h>
#include <wasm-builder.h>
namespace wasm {
struct ThreeArgs {
Expression* a;
Expression* b;
Expression* c;
};
struct UnaryArgs {
UnaryOp a;
Expression* b;
};
struct BinaryArgs {
BinaryOp a;
Expression* b;
Expression* c;
};
class TranslateToFuzzReader {
public:
TranslateToFuzzReader(Module& wasm, std::vector<char>&& input);
TranslateToFuzzReader(Module& wasm, std::string& filename);
void pickPasses(OptimizationOptions& options);
void setAllowMemory(bool allowMemory_) { allowMemory = allowMemory_; }
void setAllowOOB(bool allowOOB_) { allowOOB = allowOOB_; }
void build();
Module& wasm;
private:
Builder builder;
Random random;
bool allowMemory = true;
bool allowOOB = true;
bool allowAddingUnreachableCode;
static const bool ATOMIC_WAITS = false;
unsigned LOGGING_PERCENT = 0;
Name HANG_LIMIT_GLOBAL;
Name funcrefTableName;
std::unordered_map<Type, std::vector<Name>> globalsByType;
std::unordered_map<Type, std::vector<Name>> mutableGlobalsByType;
std::vector<Type> loggableTypes;
std::vector<HeapType> interestingHeapTypes;
std::unordered_map<HeapType, std::vector<HeapType>> interestingHeapSubTypes;
std::unordered_map<Type, std::vector<StructField>> typeStructFields;
std::unordered_map<Type, std::vector<HeapType>> typeArrays;
std::vector<StructField> mutableStructFields;
std::vector<HeapType> mutableArrays;
Index numAddedFunctions = 0;
struct FunctionCreationContext {
TranslateToFuzzReader& parent;
Function* func;
std::vector<Expression*> breakableStack; Index labelIndex = 0;
std::vector<Expression*> hangStack;
std::unordered_map<Type, std::vector<Index>> typeLocals;
FunctionCreationContext(TranslateToFuzzReader& parent, Function* func)
: parent(parent), func(func) {
parent.funcContext = this;
}
~FunctionCreationContext();
};
FunctionCreationContext* funcContext = nullptr;
public:
int nesting = 0;
struct AutoNester {
TranslateToFuzzReader& parent;
size_t amount = 1;
AutoNester(TranslateToFuzzReader& parent) : parent(parent) {
parent.nesting++;
}
~AutoNester() { parent.nesting -= amount; }
void add(size_t more) {
parent.nesting += more;
amount += more;
}
};
private:
int8_t get() { return random.get(); }
int16_t get16() { return random.get16(); }
int32_t get32() { return random.get32(); }
int64_t get64() { return random.get64(); }
float getFloat() { return random.getFloat(); }
double getDouble() { return random.getDouble(); }
Index upTo(Index x) { return random.upTo(x); }
bool oneIn(Index x) { return random.oneIn(x); }
Index upToSquared(Index x) { return random.upToSquared(x); }
template<typename T> const typename T::value_type& pick(const T& vec) {
return random.pick(vec);
}
template<typename T, typename... Args> T pick(T first, Args... args) {
return random.pick(first, args...);
}
template<typename T> using FeatureOptions = Random::FeatureOptions<T>;
template<typename T> const T pick(FeatureOptions<T>& picker) {
return random.pick(picker);
}
void setupMemory();
void setupHeapTypes();
void setupTables();
void setupGlobals();
void setupTags();
void addTag();
void finalizeMemory();
void finalizeTable();
void prepareHangLimitSupport();
void addHangLimitSupport();
void addImportLoggingSupport();
void addHashMemorySupport();
Expression* makeHangLimitCheck();
Expression* makeLogging();
Expression* makeMemoryHashLogging();
Function* addFunction();
void addHangLimitChecks(Function* func);
bool canBeArbitrarilyReplaced(Expression* curr) {
return curr->type.isDefaultable() &&
!EHUtils::containsValidDanglingPop(curr);
}
void recombine(Function* func);
void mutate(Function* func);
void fixAfterChanges(Function* func);
void modifyInitialFunctions();
void dropToLog(Function* func);
void addInvocations(Function* func);
Name makeLabel() {
return std::string("label$") + std::to_string(funcContext->labelIndex++);
}
Expression* make(Type type);
Expression* _makeConcrete(Type type);
Expression* _makenone();
Expression* _makeunreachable();
Expression* makeTrivial(Type type);
int trivialNesting = 0;
Expression* makeBlock(Type type);
Expression* makeLoop(Type type);
Expression* makeCondition();
Expression* makeMaybeBlock(Type type);
Expression* buildIf(const struct ThreeArgs& args, Type type);
Expression* makeIf(Type type);
Expression* makeTry(Type type);
Expression* makeBreak(Type type);
Expression* makeCall(Type type);
Expression* makeCallIndirect(Type type);
Expression* makeCallRef(Type type);
Expression* makeLocalGet(Type type);
Expression* makeLocalSet(Type type);
Expression* makeGlobalGet(Type type);
Expression* makeGlobalSet(Type type);
Expression* makeTupleMake(Type type);
Expression* makeTupleExtract(Type type);
Expression* makePointer();
Expression* makeNonAtomicLoad(Type type);
Expression* makeLoad(Type type);
Expression* makeNonAtomicStore(Type type);
Expression* makeStore(Type type);
Literal tweak(Literal value);
Literal makeLiteral(Type type);
Expression* makeRefFuncConst(Type type);
Expression* makeConst(Type type);
Expression* makeBasicRef(Type type);
Expression* makeCompoundRef(Type type);
Expression* makeTrappingRefUse(HeapType type);
Expression* buildUnary(const UnaryArgs& args);
Expression* makeUnary(Type type);
Expression* buildBinary(const BinaryArgs& args);
Expression* makeBinary(Type type);
Expression* buildSelect(const ThreeArgs& args, Type type);
Expression* makeSelect(Type type);
Expression* makeSwitch(Type type);
Expression* makeDrop(Type type);
Expression* makeReturn(Type type);
Expression* makeNop(Type type);
Expression* makeUnreachable(Type type);
Expression* makeAtomic(Type type);
Expression* makeSIMD(Type type);
Expression* makeSIMDExtract(Type type);
Expression* makeSIMDReplace();
Expression* makeSIMDShuffle();
Expression* makeSIMDTernary();
Expression* makeSIMDShift();
Expression* makeSIMDLoad();
Expression* makeBulkMemory(Type type);
Expression* makeRefIsNull(Type type);
Expression* makeRefEq(Type type);
Expression* makeRefTest(Type type);
Expression* makeRefCast(Type type);
Expression* makeStructGet(Type type);
Expression* makeStructSet(Type type);
Expression* makeArrayGet(Type type);
Expression* makeArraySet(Type type);
Expression* makeArrayBulkMemoryOp(Type type);
Expression* makeI31Get(Type type);
Expression* makeThrow(Type type);
Expression* makeMemoryInit();
Expression* makeDataDrop();
Expression* makeMemoryCopy();
Expression* makeMemoryFill();
Type getSingleConcreteType();
Type getReferenceType();
Type getEqReferenceType();
Type getMVPType();
Type getTupleType();
Type getConcreteType();
Type getControlFlowType();
Type getStorableType();
Type getLoggableType();
bool isLoggableType(Type type);
Nullability getNullability();
Nullability getSubType(Nullability nullability);
HeapType getSubType(HeapType type);
Type getSubType(Type type);
Nullability getSuperType(Nullability nullability);
HeapType getSuperType(HeapType type);
Type getSuperType(Type type);
Name getTargetName(Expression* target);
Type getTargetType(Expression* target);
Index logify(Index x) {
return std::floor(std::log(std::max(Index(1) + x, Index(1))));
}
};
}