diff --git a/test/evmc/mocked_host.hpp b/test/evmc/mocked_host.hpp
index c7d99e6ad..c70718d7b 100644
--- a/test/evmc/mocked_host.hpp
+++ b/test/evmc/mocked_host.hpp
@@ -108,7 +108,7 @@ public:
};
/// The set of all accounts in the Host, organized by their addresses.
- std::unordered_map
accounts;
+ std::map accounts;
/// The EVMC transaction context to be returned by get_tx_context().
evmc_tx_context tx_context = {};
diff --git a/test/tools/ossfuzz/ValueGenerator.cpp b/test/tools/ossfuzz/ValueGenerator.cpp
index 6ef532607..61cab8bdc 100644
--- a/test/tools/ossfuzz/ValueGenerator.cpp
+++ b/test/tools/ossfuzz/ValueGenerator.cpp
@@ -150,6 +150,16 @@ string fixedBytes(
}
}
+std::string ValueGenerator::addressLiteral(bool _hexPrefix)
+{
+ std::uniform_int_distribution dist(0, m_addresses.size() - 1);
+ std::string addressLiteral;
+ if (_hexPrefix)
+ addressLiteral = "0x";
+ addressLiteral += m_addresses[dist(m_rand)].hex();
+ return addressLiteral;
+}
+
void ValueGenerator::initialiseType(TypeInfo& _t)
{
switch (_t.type)
@@ -177,10 +187,14 @@ void ValueGenerator::initialiseType(TypeInfo& _t)
_t.value += "0x" + fixedBytes(static_cast(_t.fixedByteWidth), m_rand(), true);
break;
case Type::Address:
- _t.value += "0x" + fixedBytes(static_cast(FixedBytesWidth::Bytes20), m_rand(), true);
+ _t.value = addressLiteral();
break;
case Type::Function:
- _t.value += "0x" + fixedBytes(static_cast(FixedBytesWidth::Bytes24), m_rand(), true);
+ _t.value += "0x" +
+ addressLiteral(false) +
+ ":" +
+ "0x" +
+ fixedBytes(static_cast(FixedBytesWidth::Bytes4), m_rand(), true);
break;
default:
solAssert(false, "Value Generator: Invalid value type.");
diff --git a/test/tools/ossfuzz/ValueGenerator.h b/test/tools/ossfuzz/ValueGenerator.h
index 87ee84a9b..166fa36f0 100644
--- a/test/tools/ossfuzz/ValueGenerator.h
+++ b/test/tools/ossfuzz/ValueGenerator.h
@@ -18,6 +18,8 @@
#pragma once
+#include
+
#include
#include
@@ -132,10 +134,15 @@ public:
std::string name;
std::string value;
};
- explicit ValueGenerator(Json::Value const& _type, unsigned _seed):
+ explicit ValueGenerator(
+ Json::Value const& _type,
+ unsigned _seed,
+ std::vector _addresses
+ ):
m_rand(_seed),
m_type(_type),
- m_bernoulli(0.5)
+ m_bernoulli(0.5),
+ m_addresses(std::move(_addresses))
{}
void boolean()
{
@@ -173,9 +180,11 @@ public:
std::vector& _arrayInfo,
TypeInfo& _typeInfo
);
+ std::string addressLiteral(bool _hexPrefix = true);
private:
std::ostringstream m_stream;
std::minstd_rand m_rand;
Json::Value const& m_type;
std::bernoulli_distribution m_bernoulli;
+ std::vector m_addresses;
};
diff --git a/test/tools/ossfuzz/solc_ossfuzz.cpp b/test/tools/ossfuzz/solc_ossfuzz.cpp
index d48706225..c85019120 100644
--- a/test/tools/ossfuzz/solc_ossfuzz.cpp
+++ b/test/tools/ossfuzz/solc_ossfuzz.cpp
@@ -50,166 +50,200 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size);
static evmc::VM evmone = evmc::VM{evmc_create_evmone()};
static constexpr size_t abiCoderHeapSize = 1024 * 512;
+namespace
+{
+string abiEncoding(
+ Json::Value const& _functionABI,
+ vector _addressLiterals,
+ Json::Value const& _methodIdentifiers
+)
+{
+ string abiTypeString;
+ string abiValueString;
+ tie(abiTypeString, abiValueString) = ValueGenerator{
+ _functionABI["inputs"],
+ 0,
+ _addressLiterals
+ }.type();
+ string encodedData;
+ // A function with inputs must contain type names within
+ // parentheses.
+ bool functionWithInputs = abiTypeString != "()";
+ string functionSignature = _functionABI["name"].asString() + abiTypeString;
+ cout << functionSignature << endl;
+ string encoding = _methodIdentifiers[functionSignature].asString();
+ if (functionWithInputs)
+ {
+ abicoder::ABICoder coder(abiCoderHeapSize);
+ auto [status, data] = coder.encode(abiTypeString, abiValueString);
+ cout << abiTypeString << endl;
+ cout << abiValueString << endl;
+ solAssert(status, "Isabelle coder: failed.");
+ encoding += data.substr(2, data.size());
+ }
+ return encoding;
+}
+}
+
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size)
{
-// if (_size <= 600)
+ string input(reinterpret_cast(_data), _size);
+ regex re = regex("library\\s*(\\w+)\\s*\\{");
+ smatch matches;
+ std::string libraryName;
+ auto match = regex_search(input, matches, re);
+ if (match && matches[1].matched)
+ libraryName = matches[1].str();
+
+ map sourceCode;
+ try
{
- string input(reinterpret_cast(_data), _size);
- regex re = regex("library\\s*(\\w+)\\s*\\{");
- smatch matches;
- std::string libraryName;
- auto match = regex_search(input, matches, re);
- if (match && matches[1].matched)
- libraryName = matches[1].str();
+ EVMVersion version;
+ EVMHost hostContext(version, evmone);
- map sourceCode;
- try
+ TestCaseReader t = TestCaseReader(std::istringstream(input));
+ sourceCode = t.sources().sources;
+ string contractName;
+ string methodName;
+ auto compilerSetting = OptimiserSettings::standard();
+ CompilerInput cInput = {
+ version,
+ sourceCode,
+ contractName,
+ compilerSetting,
+ {},
+ true,
+ false
+ };
+ EvmoneUtility evmoneUtil(
+ hostContext,
+ cInput,
+ contractName,
+ libraryName,
+ methodName
+ );
+
+ if (!libraryName.empty()) {
+ cout << "Deploying library" << endl;
+ auto l = evmoneUtil.compileAndDeployLibrary();
+ if (!l.has_value())
+ return 0;
+ cout << "Deployed" << endl;
+ }
+
+ vector addressLiterals;
+ for (auto const& account: hostContext.accounts)
+ addressLiterals.push_back(EVMHost::convertFromEVMC(account.first));
+
+ hostContext.reset();
+ evmoneUtil.reset(true);
+ evmoneUtil.optSetting(compilerSetting);
+ auto compilerOutput = evmoneUtil.compileContract();
+ if (!compilerOutput.has_value())
+ return 0;
+
+ auto r = evmoneUtil.randomFunction(_size);
+ if (!r.has_value())
+ return 0;
+
+ auto deployResult = evmoneUtil.deployContract(compilerOutput->byteCode);
+ if (deployResult.status_code != EVMC_SUCCESS)
+ return 0;
+
+ // Add deployed contract to list of address literals.
+ addressLiterals.push_back(EVMHost::convertFromEVMC(deployResult.create_address));
+
+ string encodedData = abiEncoding(r.value(), addressLiterals,
+ compilerOutput->methodIdentifiersInContract);
+ auto callResult = evmoneUtil.executeContract(
+ solidity::util::fromHex(encodedData),
+ deployResult.create_address
+ );
+
+ if (callResult.status_code != EVMC_SUCCESS) {
+ cout << "Old code gen call failed with status code: "
+ << callResult.status_code
+ << endl;
+ return 0;
+ }
+
+ solidity::bytes result;
+ for (size_t i = 0; i < callResult.output_size; i++)
+ result.push_back(callResult.output_data[i]);
+
+ EVMHostPrinter p(hostContext, deployResult.create_address);
+ ostringstream oldCodeGen;
+ oldCodeGen << p.state();
+
+ compilerSetting.runYulOptimiser = true;
+ compilerSetting.optimizeStackAllocation = true;
+ hostContext.reset();
+ // Remove contract compiled via old code gen from list of address
+ // literals.
+ addressLiterals.pop_back();
+ evmoneUtil.reset(true);
+ evmoneUtil.optSetting(compilerSetting);
+ evmoneUtil.viaIR(true);
+ auto compilerOutputOpt = evmoneUtil.compileContract();
+ solAssert(compilerOutputOpt.has_value(), "Contract could not be optimised.");
+
+ auto deployResultOpt = evmoneUtil.deployContract(compilerOutputOpt->byteCode);
+ solAssert(deployResultOpt.status_code == EVMC_SUCCESS,
+ "Contract compiled via new code gen could not be deployed.");
+
+ // Add address literal of contract compiled via Yul IR.
+ addressLiterals.push_back(EVMHost::convertFromEVMC(deployResultOpt.create_address));
+ string encodedDataIR = abiEncoding(r.value(), addressLiterals,
+ compilerOutput->methodIdentifiersInContract);
+
+ auto callResultOpt = evmoneUtil.executeContract(
+ solidity::util::fromHex(encodedDataIR),
+ deployResultOpt.create_address
+ );
+ solAssert(callResultOpt.status_code == EVMC_SUCCESS, "New code gen contract call failed.");
+
+ solidity::bytes resultOpt;
+ for (size_t i = 0; i < callResultOpt.output_size; i++)
+ resultOpt.push_back(callResultOpt.output_data[i]);
+
+ if (result != resultOpt)
{
- EVMVersion version;
- EVMHost hostContext(version, evmone);
-
- TestCaseReader t = TestCaseReader(std::istringstream(input));
- sourceCode = t.sources().sources;
- string contractName;
- string methodName;
- auto compilerSetting = OptimiserSettings::standard();
- CompilerInput cInput = {
- version,
- sourceCode,
- contractName,
- compilerSetting,
- {},
- true,
- false
- };
- EvmoneUtility evmoneUtil(
- hostContext,
- cInput,
- contractName,
- libraryName,
- methodName
- );
-
- if (!libraryName.empty())
- {
- cout << "Deploying library" << endl;
- auto l = evmoneUtil.compileAndDeployLibrary();
- if (!l.has_value())
- return 0;
- cout << "Deployed" << endl;
- }
-
- hostContext.reset();
- evmoneUtil.reset(true);
- evmoneUtil.optSetting(compilerSetting);
- auto compilerOutput = evmoneUtil.compileContract();
- if (!compilerOutput.has_value())
- return 0;
-
- auto r = evmoneUtil.randomFunction(_size);
- if (!r.has_value())
- return 0;
-
- auto x = ValueGenerator{r.value()["inputs"], 0}.type();
- bool encodeStatus;
- string encodedData;
- bool functionWithInputs = x.first != "()";
- auto sig = r.value()["name"].asString() + x.first;
- cout << sig << endl;
- if (functionWithInputs)
- {
- abicoder::ABICoder coder(abiCoderHeapSize);
- auto s = coder.encode(x.first, x.second);
- encodeStatus = s.first;
- encodedData = s.second;
- solAssert(encodeStatus, "Isabelle coder: failed.");
- }
-
- auto deployResult = evmoneUtil.deployContract(compilerOutput->byteCode);
- if (deployResult.status_code != EVMC_SUCCESS)
- return 0;
-
- auto methodSig = compilerOutput->methodIdentifiersInContract[sig].asString();
- if (functionWithInputs)
- methodSig += encodedData.substr(2, encodedData.size());
- auto callResult = evmoneUtil.executeContract(
- solidity::util::fromHex(methodSig),
- deployResult.create_address
- );
-
- if (callResult.status_code != EVMC_SUCCESS)
- {
- cout << "Old code gen call failed with status code: "
- << callResult.status_code
- << endl;
- return 0;
- }
-
- solidity::bytes result;
- for (size_t i = 0; i < callResult.output_size; i++)
- result.push_back(callResult.output_data[i]);
-
cout << solidity::util::toHex(result) << endl;
-
- EVMHostPrinter p(hostContext, deployResult.create_address);
- ostringstream oldCodeGen;
- oldCodeGen << p.state();
-
- compilerSetting.runYulOptimiser = true;
- compilerSetting.optimizeStackAllocation = true;
- hostContext.reset();
- evmoneUtil.reset(true);
- evmoneUtil.optSetting(compilerSetting);
- evmoneUtil.viaIR(true);
- auto compilerOutputOpt = evmoneUtil.compileContract();
- solAssert(compilerOutputOpt.has_value(), "Contract could not be optimised.");
-
- auto deployResultOpt = evmoneUtil.deployContract(compilerOutputOpt->byteCode);
- solAssert(deployResultOpt.status_code == EVMC_SUCCESS, "Contract compiled via new code gen could not be deployed.");
-
- auto callResultOpt = evmoneUtil.executeContract(
- solidity::util::fromHex(methodSig),
- deployResultOpt.create_address
- );
- solAssert(callResultOpt.status_code == EVMC_SUCCESS, "New code gen contract call failed.");
-
- solidity::bytes resultOpt;
- for (size_t i = 0; i < callResultOpt.output_size; i++)
- resultOpt.push_back(callResultOpt.output_data[i]);
-
cout << solidity::util::toHex(resultOpt) << endl;
- solAssert(result == resultOpt, "Old and new code gen call results do not match.");
+ }
+ solAssert(result == resultOpt, "Old and new code gen call results do not match.");
- EVMHostPrinter pOpt(hostContext, deployResultOpt.create_address);
- ostringstream newCodeGen;
- newCodeGen << pOpt.state();
+ EVMHostPrinter pOpt(hostContext, deployResultOpt.create_address);
+ ostringstream newCodeGen;
+ newCodeGen << pOpt.state();
+ if (oldCodeGen.str() != newCodeGen.str())
+ {
cout << oldCodeGen.str() << endl;
cout << newCodeGen.str() << endl;
-
- solAssert(oldCodeGen.str() == newCodeGen.str(), "Old and new code gen state do not match.");
- return 0;
- }
- catch (runtime_error const&)
- {
- cout << "Runtime error!" << endl;
- return 0;
- }
- catch (solidity::langutil::UnimplementedFeatureError const&)
- {
- cout << "Unimplemented feature!" << endl;
- return 0;
- }
- catch (solidity::langutil::CompilerError const& _e)
- {
- cout << "Compiler error!" << endl;
- cout << _e.what() << endl;
- return 0;
- }
- catch (solidity::yul::StackTooDeepError const&)
- {
- cout << "Stack too deep" << endl;
- return 0;
}
+ solAssert(oldCodeGen.str() == newCodeGen.str(), "Old and new code gen state do not match.");
+ return 0;
+ }
+ catch (runtime_error const&)
+ {
+ cout << "Runtime error!" << endl;
+ return 0;
+ }
+ catch (solidity::langutil::UnimplementedFeatureError const&)
+ {
+ cout << "Unimplemented feature!" << endl;
+ return 0;
+ }
+ catch (solidity::langutil::CompilerError const& _e)
+ {
+ cout << "Compiler error!" << endl;
+ cout << _e.what() << endl;
+ return 0;
+ }
+ catch (solidity::yul::StackTooDeepError const&)
+ {
+ cout << "Stack too deep" << endl;
+ return 0;
}
}