mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Arithmetic fuzzer in a day
This commit is contained in:
parent
602b29cba7
commit
f92f2ed78a
@ -10,7 +10,7 @@ add_dependencies(ossfuzz
|
||||
|
||||
if (OSSFUZZ)
|
||||
add_custom_target(ossfuzz_proto)
|
||||
add_dependencies(ossfuzz_proto yul_proto_ossfuzz yul_proto_diff_ossfuzz)
|
||||
add_dependencies(ossfuzz_proto yul_proto_ossfuzz yul_proto_diff_ossfuzz sol_arith_proto_ossfuzz)
|
||||
|
||||
add_custom_target(ossfuzz_abiv2)
|
||||
add_dependencies(ossfuzz_abiv2 abiv2_proto_ossfuzz)
|
||||
@ -78,6 +78,48 @@ if (OSSFUZZ)
|
||||
protobuf.a
|
||||
)
|
||||
set_target_properties(abiv2_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
|
||||
|
||||
add_executable(sol_arith_proto_ossfuzz
|
||||
solArithProtoFuzzer.cpp
|
||||
solarithprotoToSol.cpp
|
||||
solArith.pb.cc
|
||||
abiV2FuzzerCommon.cpp
|
||||
../../EVMHost.cpp
|
||||
)
|
||||
target_include_directories(sol_arith_proto_ossfuzz PRIVATE
|
||||
/usr/include/libprotobuf-mutator
|
||||
)
|
||||
target_link_libraries(sol_arith_proto_ossfuzz PRIVATE solidity libsolc
|
||||
evmc
|
||||
evmone-standalone
|
||||
protobuf-mutator-libfuzzer.a
|
||||
protobuf-mutator.a
|
||||
protobuf.a
|
||||
)
|
||||
set_target_properties(sol_arith_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
|
||||
|
||||
# add_executable(sol_proto_ossfuzz
|
||||
# solProtoFuzzer.cpp
|
||||
# protoToSol.cpp
|
||||
# solProto.pb.cc
|
||||
# abiV2FuzzerCommon.cpp
|
||||
# ../../EVMHost.cpp
|
||||
# SolProtoAdaptor.cpp
|
||||
# )
|
||||
# target_include_directories(sol_proto_ossfuzz PRIVATE
|
||||
# /usr/include/libprotobuf-mutator
|
||||
# /home/bhargava/work/github/solidity/deps/LPM/external.protobuf/include
|
||||
# /home/bhargava/work/github/solidity/deps/evmone/include
|
||||
# /home/bhargava/work/github/solidity/deps/libprotobuf-mutator
|
||||
# )
|
||||
# target_link_libraries(sol_proto_ossfuzz PRIVATE solidity libsolc
|
||||
# evmc
|
||||
# evmone-standalone
|
||||
# protobuf-mutator-libfuzzer.a
|
||||
# protobuf-mutator.a
|
||||
# protobuf.a
|
||||
# )
|
||||
# set_target_properties(sol_proto_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
|
||||
else()
|
||||
add_library(solc_opt_ossfuzz
|
||||
solc_opt_ossfuzz.cpp
|
||||
|
116
test/tools/ossfuzz/solArith.proto
Normal file
116
test/tools/ossfuzz/solArith.proto
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
message Type {
|
||||
enum Sign {
|
||||
SIGNED = 0;
|
||||
UNSIGNED = 1;
|
||||
}
|
||||
required Sign s = 1;
|
||||
required uint32 bytewidth = 2;
|
||||
}
|
||||
|
||||
message UnaryOpStmt {
|
||||
enum Op {
|
||||
POSTINC = 1;
|
||||
POSTDEC = 2;
|
||||
PREINC = 3;
|
||||
PREDEC = 4;
|
||||
}
|
||||
required Op op = 1;
|
||||
required VarRef v = 2;
|
||||
}
|
||||
|
||||
message BinaryOpStmt {
|
||||
enum Op {
|
||||
ADDSELF = 0;
|
||||
SUBSELF = 1;
|
||||
MULSELF = 2;
|
||||
DIVSELF = 3;
|
||||
MODSELF = 4;
|
||||
SHLSELF = 5;
|
||||
SHRSELF = 6;
|
||||
}
|
||||
required Op op = 1;
|
||||
required VarRef left = 2;
|
||||
required Expression right = 3;
|
||||
}
|
||||
|
||||
message BinaryOp {
|
||||
enum Op {
|
||||
ADD = 0;
|
||||
SUB = 1;
|
||||
MUL = 2;
|
||||
DIV = 3;
|
||||
MOD = 4;
|
||||
EXP = 10;
|
||||
SHL = 11;
|
||||
SHR = 12;
|
||||
}
|
||||
required Op op = 1;
|
||||
required Expression left = 2;
|
||||
required Expression right = 3;
|
||||
}
|
||||
|
||||
message VarDecl {
|
||||
required Type t = 1;
|
||||
required Expression value = 2;
|
||||
}
|
||||
|
||||
message Assignment {
|
||||
required VarRef id = 1;
|
||||
required Expression value = 2;
|
||||
}
|
||||
|
||||
message VarRef {
|
||||
required uint32 id = 1;
|
||||
}
|
||||
|
||||
message Expression {
|
||||
oneof expr_oneof {
|
||||
VarRef v = 1;
|
||||
BinaryOp bop = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message Return {
|
||||
required Expression e = 1;
|
||||
}
|
||||
|
||||
message Statement {
|
||||
oneof stmt_oneof {
|
||||
VarDecl vd = 1;
|
||||
Assignment a = 2;
|
||||
UnaryOpStmt u = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message Block {
|
||||
required VarDecl v = 1;
|
||||
repeated Statement s = 2;
|
||||
required Return r = 3;
|
||||
}
|
||||
|
||||
message Program {
|
||||
required Block b = 1;
|
||||
required Type.Sign s = 2;
|
||||
required uint64 seed = 3;
|
||||
}
|
||||
|
||||
package solidity.test.solarithfuzzer;
|
255
test/tools/ossfuzz/solArithProtoFuzzer.cpp
Normal file
255
test/tools/ossfuzz/solArithProtoFuzzer.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <test/tools/ossfuzz/solarithprotoToSol.h>
|
||||
#include <test/tools/ossfuzz/solArith.pb.h>
|
||||
#include <test/tools/ossfuzz/abiV2FuzzerCommon.h>
|
||||
#include <test/EVMHost.h>
|
||||
|
||||
#include <evmone/evmone.h>
|
||||
#include <src/libfuzzer/libfuzzer_macro.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
static evmc::VM evmone = evmc::VM{evmc_create_evmone()};
|
||||
|
||||
using namespace solidity::test::abiv2fuzzer;
|
||||
using namespace solidity::test::solarithfuzzer;
|
||||
using namespace solidity;
|
||||
using namespace solidity::test;
|
||||
using namespace solidity::util;
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
/// Test function returns a uint256 value
|
||||
//static size_t const expectedOutputLength = 32;
|
||||
///// Expected output value is decimal 0
|
||||
//static uint8_t const expectedOutput[expectedOutputLength] = {
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
//};
|
||||
|
||||
/// Compares the contents of the memory address pointed to
|
||||
/// by `_result` of `_length` bytes to the expected output.
|
||||
/// Returns true if `_result` matches expected output, false
|
||||
/// otherwise.
|
||||
//bool isOutputExpected(evmc::result const& _run)
|
||||
//{
|
||||
// if (_run.output_size != expectedOutputLength)
|
||||
// return false;
|
||||
//
|
||||
// return (memcmp(_run.output_data, expectedOutput, expectedOutputLength) == 0);
|
||||
//}
|
||||
|
||||
bool compareRuns(evmc::result const& _run1, evmc::result const& _run2)
|
||||
{
|
||||
if (_run1.output_size != _run2.output_size)
|
||||
return false;
|
||||
return memcmp(_run1.output_data, _run2.output_data, _run1.output_size) == 0;
|
||||
}
|
||||
|
||||
/// Accepts a reference to a user-specified input and returns an
|
||||
/// evmc_message with all of its fields zero initialized except
|
||||
/// gas and input fields.
|
||||
/// The gas field is set to the maximum permissible value so that we
|
||||
/// don't run into out of gas errors. The input field is copied from
|
||||
/// user input.
|
||||
evmc_message initializeMessage(bytes const& _input)
|
||||
{
|
||||
// Zero initialize all message fields
|
||||
evmc_message msg = {};
|
||||
// Gas available (value of type int64_t) is set to its maximum
|
||||
// value.
|
||||
msg.gas = std::numeric_limits<int64_t>::max();
|
||||
msg.input_data = _input.data();
|
||||
msg.input_size = _input.size();
|
||||
return msg;
|
||||
}
|
||||
|
||||
/// Accepts host context implementation, and keccak256 hash of the function
|
||||
/// to be called at a specified address in the simulated blockchain as
|
||||
/// input and returns the result of the execution of the called function.
|
||||
evmc::result executeContract(
|
||||
EVMHost& _hostContext,
|
||||
bytes const& _functionHash,
|
||||
evmc_address _deployedAddress
|
||||
)
|
||||
{
|
||||
evmc_message message = initializeMessage(_functionHash);
|
||||
message.destination = _deployedAddress;
|
||||
message.kind = EVMC_CALL;
|
||||
return _hostContext.call(message);
|
||||
}
|
||||
|
||||
/// Accepts a reference to host context implementation and byte code
|
||||
/// as input and deploys it on the simulated blockchain. Returns the
|
||||
/// result of deployment.
|
||||
evmc::result deployContract(EVMHost& _hostContext, bytes const& _code)
|
||||
{
|
||||
evmc_message message = initializeMessage(_code);
|
||||
message.kind = EVMC_CREATE;
|
||||
return _hostContext.call(message);
|
||||
}
|
||||
|
||||
std::pair<bytes, Json::Value> compileContract(
|
||||
std::string _sourceCode,
|
||||
std::string _contractName,
|
||||
std::map<std::string, solidity::util::h160> const& _libraryAddresses = {},
|
||||
frontend::OptimiserSettings _optimization = frontend::OptimiserSettings::minimal()
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Compile contract generated by the proto fuzzer
|
||||
SolidityCompilationFramework solCompilationFramework;
|
||||
return std::make_pair(
|
||||
solCompilationFramework.compileContract(_sourceCode, _contractName, _libraryAddresses, _optimization),
|
||||
solCompilationFramework.getMethodIdentifiers()
|
||||
);
|
||||
}
|
||||
// Ignore stack too deep errors during compilation
|
||||
catch (evmasm::StackTooDeepException const&)
|
||||
{
|
||||
return std::make_pair(bytes{}, Json::Value(0));
|
||||
}
|
||||
}
|
||||
|
||||
evmc::result deployAndExecute(EVMHost& _hostContext, bytes _byteCode, std::string _hexEncodedInput)
|
||||
{
|
||||
// Deploy contract and signal failure if deploy failed
|
||||
evmc::result createResult = deployContract(_hostContext, _byteCode);
|
||||
solAssert(
|
||||
createResult.status_code == EVMC_SUCCESS,
|
||||
"Proto solc fuzzer: Contract creation failed"
|
||||
);
|
||||
|
||||
// Execute test function and signal failure if EVM reverted or
|
||||
// did not return expected output on successful execution.
|
||||
evmc::result callResult = executeContract(
|
||||
_hostContext,
|
||||
fromHex(_hexEncodedInput),
|
||||
createResult.create_address
|
||||
);
|
||||
|
||||
// We don't care about EVM One failures other than EVMC_REVERT
|
||||
solAssert(callResult.status_code != EVMC_REVERT, "Proto solc fuzzer: EVM One reverted");
|
||||
return callResult;
|
||||
}
|
||||
|
||||
evmc::result compileDeployAndExecute(
|
||||
std::string _sourceCode,
|
||||
std::string _contractName,
|
||||
std::string _methodName,
|
||||
frontend::OptimiserSettings _optimization,
|
||||
std::string _libraryName = {}
|
||||
)
|
||||
{
|
||||
bytes libraryBytecode;
|
||||
Json::Value libIds;
|
||||
// We target the default EVM which is the latest
|
||||
langutil::EVMVersion version = {};
|
||||
EVMHost hostContext(version, evmone);
|
||||
std::map<std::string, solidity::util::h160> _libraryAddressMap;
|
||||
|
||||
// First deploy library
|
||||
if (!_libraryName.empty())
|
||||
{
|
||||
tie(libraryBytecode, libIds) = compileContract(
|
||||
_sourceCode,
|
||||
_libraryName,
|
||||
{},
|
||||
_optimization
|
||||
);
|
||||
// Deploy contract and signal failure if deploy failed
|
||||
evmc::result createResult = deployContract(hostContext, libraryBytecode);
|
||||
solAssert(
|
||||
createResult.status_code == EVMC_SUCCESS,
|
||||
"Proto solc fuzzer: Library deployment failed"
|
||||
);
|
||||
_libraryAddressMap[_libraryName] = EVMHost::convertFromEVMC(createResult.create_address);
|
||||
}
|
||||
|
||||
auto [bytecode, ids] = compileContract(
|
||||
_sourceCode,
|
||||
_contractName,
|
||||
_libraryAddressMap,
|
||||
_optimization
|
||||
);
|
||||
|
||||
return deployAndExecute(
|
||||
hostContext,
|
||||
bytecode,
|
||||
ids[_methodName].asString()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_PROTO_FUZZER(Program const& _input)
|
||||
{
|
||||
ProtoConverter converter;
|
||||
string sol_source = converter.programToString(_input);
|
||||
|
||||
if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH"))
|
||||
{
|
||||
// With libFuzzer binary run this to generate a YUL source file x.yul:
|
||||
// PROTO_FUZZER_DUMP_PATH=x.yul ./a.out proto-input
|
||||
ofstream of(dump_path);
|
||||
of.write(sol_source.data(), sol_source.size());
|
||||
}
|
||||
|
||||
if (const char* dump_path = getenv("SOL_DEBUG_FILE"))
|
||||
{
|
||||
sol_source.clear();
|
||||
// With libFuzzer binary run this to generate a YUL source file x.yul:
|
||||
// PROTO_FUZZER_LOAD_PATH=x.yul ./a.out proto-input
|
||||
ifstream ifstr(dump_path);
|
||||
sol_source = {
|
||||
std::istreambuf_iterator<char>(ifstr),
|
||||
std::istreambuf_iterator<char>()
|
||||
};
|
||||
std::cout << sol_source << std::endl;
|
||||
}
|
||||
|
||||
auto minimalResult = compileDeployAndExecute(
|
||||
sol_source,
|
||||
":C",
|
||||
"test()",
|
||||
frontend::OptimiserSettings::minimal(),
|
||||
""
|
||||
);
|
||||
bool successState = minimalResult.status_code == EVMC_SUCCESS;
|
||||
|
||||
auto optResult = compileDeployAndExecute(
|
||||
sol_source,
|
||||
":C",
|
||||
"test()",
|
||||
frontend::OptimiserSettings::standard(),
|
||||
""
|
||||
);
|
||||
if (successState)
|
||||
{
|
||||
solAssert(
|
||||
optResult.status_code == EVMC_SUCCESS,
|
||||
"Sol arith fuzzer: Optimal code failed"
|
||||
);
|
||||
solAssert(
|
||||
compareRuns(minimalResult, optResult),
|
||||
"Sol arith fuzzer: Runs produced different result"
|
||||
);
|
||||
}
|
||||
}
|
199
test/tools/ossfuzz/solarithprotoToSol.cpp
Normal file
199
test/tools/ossfuzz/solarithprotoToSol.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
#include <test/tools/ossfuzz/solarithprotoToSol.h>
|
||||
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <libsolutil/Whiskers.h>
|
||||
|
||||
using namespace solidity::test::solarithfuzzer;
|
||||
using namespace solidity;
|
||||
using namespace solidity::util;
|
||||
using namespace std;
|
||||
|
||||
string ProtoConverter::programToString(Program const& _program)
|
||||
{
|
||||
m_rand = make_unique<SolRandomNumGenerator>(
|
||||
SolRandomNumGenerator(_program.seed())
|
||||
);
|
||||
return visit(_program);
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Program const& _program)
|
||||
{
|
||||
Whiskers p(R"(pragma solidity >= 0.0.0;)");
|
||||
Whiskers c(R"(contract C {)");
|
||||
Whiskers t(R"(function test() public returns (<type>)<body>)");
|
||||
m_returnType = signString(_program.s());
|
||||
t("type", m_returnType);
|
||||
t("body", visit(_program.b()));
|
||||
return p.render()
|
||||
+ '\n'
|
||||
+ c.render()
|
||||
+ '\n'
|
||||
+ '\t'
|
||||
+ t.render()
|
||||
+ '\n'
|
||||
+ '}';
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Return const& _ret)
|
||||
{
|
||||
Whiskers r(R"(return <type>(<expr>);)");
|
||||
r("expr", visit(_ret.e()));
|
||||
r("type", m_returnType);
|
||||
return "\t\t" + r.render() + '\n';
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Block const& _block)
|
||||
{
|
||||
ostringstream blockStr;
|
||||
blockStr << '\n'
|
||||
<< '\t'
|
||||
<< '{'
|
||||
<< '\n';
|
||||
blockStr << visit(_block.v());
|
||||
for (auto const& s: _block.s())
|
||||
blockStr << visit(s);
|
||||
blockStr << visit(_block.r());
|
||||
blockStr << '\n'
|
||||
<< '\t'
|
||||
<< '}';
|
||||
return blockStr.str();
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Statement const& _stmt)
|
||||
{
|
||||
switch (_stmt.stmt_oneof_case())
|
||||
{
|
||||
case Statement::kVd:
|
||||
return visit(_stmt.vd());
|
||||
case Statement::kA:
|
||||
return visit(_stmt.a());
|
||||
case Statement::kU:
|
||||
return visit(_stmt.u());
|
||||
case Statement::STMT_ONEOF_NOT_SET:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(VarDecl const& _vardecl)
|
||||
{
|
||||
bool varExists = varAvailable();
|
||||
Whiskers v(R"(<type> <varName> = <type>(<value>);)");
|
||||
string type = visit(_vardecl.t());
|
||||
string varName = newVarName();
|
||||
m_varTypeMap.emplace(varName, type);
|
||||
v("type", type);
|
||||
v("varName", varName);
|
||||
v("value", varExists ? visit(_vardecl.value()) : to_string((*m_rand)()));
|
||||
incrementVarCounter();
|
||||
return "\t\t" + v.render() + '\n';
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Type const& _type)
|
||||
{
|
||||
return signString(_type.s()) + widthString(_type.bytewidth());
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(UnaryOpStmt const& _uop)
|
||||
{
|
||||
switch (_uop.op())
|
||||
{
|
||||
case UnaryOpStmt_Op_POSTINC:
|
||||
return "\t\t" + visit(_uop.v()) + "++;\n";
|
||||
case UnaryOpStmt_Op_POSTDEC:
|
||||
return "\t\t" + visit(_uop.v()) + "--;\n";
|
||||
case UnaryOpStmt_Op_PREINC:
|
||||
return "\t\t++" + visit(_uop.v()) + ";\n";
|
||||
case UnaryOpStmt_Op_PREDEC:
|
||||
return "\t\t--" + visit(_uop.v()) + ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(BinaryOp const& _bop)
|
||||
{
|
||||
string op{};
|
||||
switch (_bop.op())
|
||||
{
|
||||
case BinaryOp_Op_ADD:
|
||||
op = " + ";
|
||||
break;
|
||||
case BinaryOp_Op_SUB:
|
||||
op = " - ";
|
||||
break;
|
||||
case BinaryOp_Op_MUL:
|
||||
op = " * ";
|
||||
break;
|
||||
case BinaryOp_Op_DIV:
|
||||
op = " / ";
|
||||
break;
|
||||
case BinaryOp_Op_MOD:
|
||||
op = " % ";
|
||||
break;
|
||||
// case BinaryOp_Op_ADDSELF:
|
||||
// op = " += ";
|
||||
// break;
|
||||
// case BinaryOp_Op_SUBSELF:
|
||||
// op = " -= ";
|
||||
// break;
|
||||
// case BinaryOp_Op_MULSELF:
|
||||
// op = " *= ";
|
||||
// break;
|
||||
// case BinaryOp_Op_DIVSELF:
|
||||
// op = " /= ";
|
||||
// break;
|
||||
// case BinaryOp_Op_MODSELF:
|
||||
// op = " %= ";
|
||||
// break;
|
||||
case BinaryOp_Op_EXP:
|
||||
op = " ** ";
|
||||
break;
|
||||
case BinaryOp_Op_SHL:
|
||||
op = " << ";
|
||||
break;
|
||||
case BinaryOp_Op_SHR:
|
||||
op = " >> ";
|
||||
break;
|
||||
// case BinaryOp_Op_SHLSELF:
|
||||
// op = " <<= ";
|
||||
// break;
|
||||
// case BinaryOp_Op_SHRSELF:
|
||||
// op = " >>= ";
|
||||
// break;
|
||||
}
|
||||
return visit(_bop.left()) + op + visit(_bop.right());
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Expression const& _expr)
|
||||
{
|
||||
switch (_expr.expr_oneof_case())
|
||||
{
|
||||
case Expression::kV:
|
||||
solAssert(varAvailable(), "Sol arith fuzzer: Varref unavaileble");
|
||||
return visit(_expr.v());
|
||||
case Expression::kBop:
|
||||
return visit(_expr.bop());
|
||||
case Expression::EXPR_ONEOF_NOT_SET:
|
||||
return "v0";
|
||||
}
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(VarRef const&)
|
||||
{
|
||||
return randomVarName();
|
||||
}
|
||||
|
||||
string ProtoConverter::visit(Assignment const& _assignment)
|
||||
{
|
||||
if (varAvailable())
|
||||
{
|
||||
string varName = visit(_assignment.id());
|
||||
solAssert(m_varTypeMap.count(varName), "Sol arith fuzzer: Invalid varname");
|
||||
Whiskers a(R"(<varName> = <type>(<expr>);)");
|
||||
a("varName", varName);
|
||||
a("type", m_varTypeMap[varName]);
|
||||
a("expr", visit(_assignment.value()));
|
||||
return "\t\t" + a.render() + '\n';
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
114
test/tools/ossfuzz/solarithprotoToSol.h
Normal file
114
test/tools/ossfuzz/solarithprotoToSol.h
Normal file
@ -0,0 +1,114 @@
|
||||
#include <test/tools/ossfuzz/solArith.pb.h>
|
||||
|
||||
#include <random>
|
||||
|
||||
namespace solidity::test::solarithfuzzer
|
||||
{
|
||||
/// Random number generator that is seeded with a fuzzer
|
||||
/// supplied unsigned integer.
|
||||
struct SolRandomNumGenerator
|
||||
{
|
||||
using RandomEngine = std::mt19937_64;
|
||||
|
||||
explicit SolRandomNumGenerator(unsigned _seed): m_random(RandomEngine(_seed)) {}
|
||||
|
||||
/// @returns a pseudo random unsigned integer
|
||||
unsigned operator()()
|
||||
{
|
||||
return m_random();
|
||||
}
|
||||
|
||||
RandomEngine m_random;
|
||||
};
|
||||
|
||||
enum class Sign
|
||||
{
|
||||
Signed,
|
||||
Unsigned
|
||||
};
|
||||
|
||||
struct SolVarRef
|
||||
{
|
||||
SolVarRef(VarRef const& _varref);
|
||||
|
||||
std::string str();
|
||||
|
||||
Sign m_sign;
|
||||
};
|
||||
|
||||
struct SolExpression
|
||||
{
|
||||
SolExpression(Expression const& _e);
|
||||
|
||||
std::string str();
|
||||
|
||||
Sign m_sign;
|
||||
};
|
||||
|
||||
struct SolBinop
|
||||
{
|
||||
SolBinop(SolExpression const& _left, SolExpression const& _right);
|
||||
|
||||
std::string str();
|
||||
|
||||
Sign m_sign;
|
||||
};
|
||||
|
||||
class ProtoConverter
|
||||
{
|
||||
public:
|
||||
ProtoConverter()
|
||||
{
|
||||
|
||||
}
|
||||
ProtoConverter(ProtoConverter const&) = delete;
|
||||
ProtoConverter(ProtoConverter&&) = delete;
|
||||
std::string programToString(Program const& _input);
|
||||
private:
|
||||
std::string visit(Type const& _type);
|
||||
std::string visit(UnaryOpStmt const& _uop);
|
||||
std::string visit(BinaryOp const& _bop);
|
||||
std::string visit(VarDecl const& _decl);
|
||||
std::string visit(Assignment const& _assignment);
|
||||
std::string visit(Return const& _return);
|
||||
std::string visit(VarRef const& _varref);
|
||||
std::string visit(Expression const& _expr);
|
||||
std::string visit(Statement const& _stmt);
|
||||
std::string visit(Block const& _block);
|
||||
std::string visit(Program const& _program);
|
||||
|
||||
std::string newVarName()
|
||||
{
|
||||
return "v" + std::to_string(m_varCounter);
|
||||
}
|
||||
void incrementVarCounter()
|
||||
{
|
||||
m_varCounter++;
|
||||
}
|
||||
std::string randomVarName()
|
||||
{
|
||||
return "v" + std::to_string((*m_rand)() % m_varCounter);
|
||||
}
|
||||
static std::string signString(Type::Sign _sign)
|
||||
{
|
||||
return _sign == Type::Sign::Type_Sign_SIGNED ? "uint" : "uint";
|
||||
}
|
||||
static std::string widthString(unsigned _width)
|
||||
{
|
||||
return std::to_string((_width % 32 + 1) * 8);
|
||||
}
|
||||
bool varAvailable()
|
||||
{
|
||||
return m_varCounter > 0;
|
||||
}
|
||||
Sign typeSign(Type const& _ts)
|
||||
{
|
||||
return _ts.s() == Type::SIGNED ? Sign::Signed : Sign::Unsigned;
|
||||
}
|
||||
|
||||
unsigned m_varCounter = 0;
|
||||
std::shared_ptr<SolRandomNumGenerator> m_rand;
|
||||
std::map<std::string, std::string> m_varTypeMap;
|
||||
std::string m_returnType;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user