#include "shell-interface.h"
#include "wasm.h"
namespace wasm {
typedef std::vector<Literal> Loggings;
struct LoggingExternalInterface : public ShellExternalInterface {
Loggings& loggings;
LoggingExternalInterface(Loggings& loggings) : loggings(loggings) {}
Literals callImport(Function* import, LiteralList& arguments) override {
if (import->module == "fuzzing-support") {
std::cout << "[LoggingExternalInterface logging";
loggings.push_back(Literal()); for (auto argument : arguments) {
std::cout << ' ' << argument;
loggings.push_back(argument);
}
std::cout << "]\n";
}
return {};
}
};
struct ExecutionResults {
std::map<Name, Literals> results;
Loggings loggings;
void get(Module& wasm) {
LoggingExternalInterface interface(loggings);
try {
ModuleInstance instance(wasm, &interface);
for (auto& exp : wasm.exports) {
if (exp->kind != ExternalKind::Function) {
continue;
}
std::cout << "[fuzz-exec] calling " << exp->name << "\n";
auto* func = wasm.getFunction(exp->value);
if (func->sig.results != Type::none) {
Literals ret = run(func, wasm, instance);
for (Literal& val : ret) {
if (val.type == Type::funcref && !val.isNull()) {
val = Literal::makeFunc(Name("funcref"));
}
}
results[exp->name] = ret;
if (ret.size() > 0) {
std::cout << "[fuzz-exec] note result: " << exp->name << " => "
<< ret << '\n';
}
} else {
run(func, wasm, instance);
}
}
} catch (const TrapException&) {
}
}
void check(Module& wasm) {
ExecutionResults optimizedResults;
optimizedResults.get(wasm);
if (optimizedResults != *this) {
std::cout << "[fuzz-exec] optimization passes changed execution results";
exit(1);
}
}
bool operator==(ExecutionResults& other) {
for (auto& iter : other.results) {
auto name = iter.first;
if (results.find(name) == results.end()) {
std::cout << "[fuzz-exec] missing " << name << '\n';
return false;
}
std::cout << "[fuzz-exec] comparing " << name << '\n';
if (results[name] != other.results[name]) {
std::cout << "not identical! " << results[name]
<< " != " << other.results[name] << "\n";
return false;
}
}
if (loggings != other.loggings) {
std::cout << "logging not identical!\n";
return false;
}
return true;
}
bool operator!=(ExecutionResults& other) { return !((*this) == other); }
Literals run(Function* func, Module& wasm) {
LoggingExternalInterface interface(loggings);
try {
ModuleInstance instance(wasm, &interface);
return run(func, wasm, instance);
} catch (const TrapException&) {
return {};
}
}
Literals run(Function* func, Module& wasm, ModuleInstance& instance) {
try {
LiteralList arguments;
if (auto* ex = wasm.getExportOrNull("hangLimitInitializer")) {
instance.callFunction(ex->value, arguments);
}
for (const auto& param : func->sig.params) {
arguments.push_back(Literal::makeZero(param));
}
return instance.callFunction(func->name, arguments);
} catch (const TrapException&) {
return {};
}
}
};
}