mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add adaptor and support library and interface inheritance
This commit is contained in:
parent
1d533694e5
commit
8973ca3c85
@ -42,6 +42,7 @@ struct InternalCompilerError: virtual util::Exception {};
|
|||||||
struct FatalError: virtual util::Exception {};
|
struct FatalError: virtual util::Exception {};
|
||||||
struct UnimplementedFeatureError: virtual util::Exception {};
|
struct UnimplementedFeatureError: virtual util::Exception {};
|
||||||
struct InvalidAstError: virtual util::Exception {};
|
struct InvalidAstError: virtual util::Exception {};
|
||||||
|
struct FuzzerError: virtual util::Exception {};
|
||||||
|
|
||||||
/// Assertion that throws an InternalCompilerError containing the given description if it is not met.
|
/// Assertion that throws an InternalCompilerError containing the given description if it is not met.
|
||||||
#define solAssert(CONDITION, DESCRIPTION) \
|
#define solAssert(CONDITION, DESCRIPTION) \
|
||||||
|
@ -219,8 +219,9 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
|
|||||||
else
|
else
|
||||||
solUnimplemented("Copying of type " + _sourceType.toString(false) + " to storage not yet supported.");
|
solUnimplemented("Copying of type " + _sourceType.toString(false) + " to storage not yet supported.");
|
||||||
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] <source_value>...
|
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] <source_value>...
|
||||||
solAssert(
|
assertThrow(
|
||||||
2 + byteOffsetSize + sourceBaseType->sizeOnStack() <= 16,
|
2 + byteOffsetSize + sourceBaseType->sizeOnStack() <= 16,
|
||||||
|
CompilerError,
|
||||||
"Stack too deep, try removing local variables."
|
"Stack too deep, try removing local variables."
|
||||||
);
|
);
|
||||||
// fetch target storage reference
|
// fetch target storage reference
|
||||||
|
@ -455,7 +455,11 @@ void CompilerUtils::encodeToMemory(
|
|||||||
// leave end_of_mem as dyn head pointer
|
// leave end_of_mem as dyn head pointer
|
||||||
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
|
||||||
dynPointers++;
|
dynPointers++;
|
||||||
solAssert((argSize + dynPointers) < 16, "Stack too deep, try using fewer variables.");
|
assertThrow(
|
||||||
|
(argSize + dynPointers) < 16,
|
||||||
|
CompilerError,
|
||||||
|
"Stack too deep, try using fewer variables."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -497,8 +501,9 @@ void CompilerUtils::encodeToMemory(
|
|||||||
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
|
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
|
||||||
{
|
{
|
||||||
// copy tail pointer (=mem_end - mem_start) to memory
|
// copy tail pointer (=mem_end - mem_start) to memory
|
||||||
solAssert(
|
assertThrow(
|
||||||
(2 + dynPointers) <= 16,
|
(2 + dynPointers) <= 16,
|
||||||
|
CompilerError,
|
||||||
"Stack too deep(" + to_string(2 + dynPointers) + "), try using fewer variables."
|
"Stack too deep(" + to_string(2 + dynPointers) + "), try using fewer variables."
|
||||||
);
|
);
|
||||||
m_context << dupInstruction(2 + dynPointers) << Instruction::DUP2;
|
m_context << dupInstruction(2 + dynPointers) << Instruction::DUP2;
|
||||||
@ -1251,7 +1256,11 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
|
|||||||
|
|
||||||
void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
|
void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
|
||||||
{
|
{
|
||||||
solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables.");
|
assertThrow(
|
||||||
|
_stackDepth <= 16,
|
||||||
|
CompilerError,
|
||||||
|
"Stack too deep, try removing local variables."
|
||||||
|
);
|
||||||
for (unsigned i = 0; i < _itemSize; ++i)
|
for (unsigned i = 0; i < _itemSize; ++i)
|
||||||
m_context << dupInstruction(_stackDepth);
|
m_context << dupInstruction(_stackDepth);
|
||||||
}
|
}
|
||||||
@ -1273,14 +1282,22 @@ void CompilerUtils::moveIntoStack(unsigned _stackDepth, unsigned _itemSize)
|
|||||||
|
|
||||||
void CompilerUtils::rotateStackUp(unsigned _items)
|
void CompilerUtils::rotateStackUp(unsigned _items)
|
||||||
{
|
{
|
||||||
solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables.");
|
assertThrow(
|
||||||
|
_items - 1 <= 16,
|
||||||
|
CompilerError,
|
||||||
|
"Stack too deep, try removing local variables."
|
||||||
|
);
|
||||||
for (unsigned i = 1; i < _items; ++i)
|
for (unsigned i = 1; i < _items; ++i)
|
||||||
m_context << swapInstruction(_items - i);
|
m_context << swapInstruction(_items - i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerUtils::rotateStackDown(unsigned _items)
|
void CompilerUtils::rotateStackDown(unsigned _items)
|
||||||
{
|
{
|
||||||
solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables.");
|
assertThrow(
|
||||||
|
_items - 1 <= 16,
|
||||||
|
CompilerError,
|
||||||
|
"Stack too deep, try removing local variables."
|
||||||
|
);
|
||||||
for (unsigned i = 1; i < _items; ++i)
|
for (unsigned i = 1; i < _items; ++i)
|
||||||
m_context << swapInstruction(i);
|
m_context << swapInstruction(i);
|
||||||
}
|
}
|
||||||
|
@ -208,8 +208,9 @@ void CodeGenerator::assemble(
|
|||||||
}
|
}
|
||||||
catch (StackTooDeepError const& _e)
|
catch (StackTooDeepError const& _e)
|
||||||
{
|
{
|
||||||
yulAssert(
|
assertThrow(
|
||||||
false,
|
false,
|
||||||
|
CompilerError,
|
||||||
"Stack too deep when compiling inline assembly" +
|
"Stack too deep when compiling inline assembly" +
|
||||||
(_e.comment() ? ": " + *_e.comment() : ".")
|
(_e.comment() ? ": " + *_e.comment() : ".")
|
||||||
);
|
);
|
||||||
|
@ -85,7 +85,7 @@ void FuzzerUtil::testCompiler(string const& _input, bool _optimize)
|
|||||||
compiler.setOptimiserSettings(optimiserSettings);
|
compiler.setOptimiserSettings(optimiserSettings);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
compiler.compile();
|
solAssert(compiler.compile(), "Compilation failed");
|
||||||
}
|
}
|
||||||
catch (Error const&)
|
catch (Error const&)
|
||||||
{
|
{
|
||||||
@ -96,6 +96,12 @@ void FuzzerUtil::testCompiler(string const& _input, bool _optimize)
|
|||||||
catch (UnimplementedFeatureError const&)
|
catch (UnimplementedFeatureError const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
catch (CompilerError const&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (StackTooDeepException const&)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FuzzerUtil::runCompiler(string const& _input, bool _quiet)
|
void FuzzerUtil::runCompiler(string const& _input, bool _quiet)
|
||||||
|
662
test/tools/ossfuzz/SolProtoAdaptor.cpp
Normal file
662
test/tools/ossfuzz/SolProtoAdaptor.cpp
Normal file
@ -0,0 +1,662 @@
|
|||||||
|
/*
|
||||||
|
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/SolProtoAdaptor.h>
|
||||||
|
|
||||||
|
#include <liblangutil/Exceptions.h>
|
||||||
|
|
||||||
|
#include <libsolutil/Whiskers.h>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace solidity::test::solprotofuzzer::adaptor;
|
||||||
|
using namespace solidity::test::solprotofuzzer;
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity::util;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
SolFunctionStateMutability mutabilityConverter(InterfaceFunction_StateMutability _mut)
|
||||||
|
{
|
||||||
|
switch (_mut)
|
||||||
|
{
|
||||||
|
case InterfaceFunction_StateMutability_PURE:
|
||||||
|
return SolFunctionStateMutability::PURE;
|
||||||
|
case InterfaceFunction_StateMutability_VIEW:
|
||||||
|
return SolFunctionStateMutability::VIEW;
|
||||||
|
case InterfaceFunction_StateMutability_PAYABLE:
|
||||||
|
return SolFunctionStateMutability::PAYABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SolFunctionStateMutability mutabilityConverter(ContractFunction_StateMutability _mut)
|
||||||
|
{
|
||||||
|
switch (_mut)
|
||||||
|
{
|
||||||
|
case ContractFunction_StateMutability_PURE:
|
||||||
|
return SolFunctionStateMutability::PURE;
|
||||||
|
case ContractFunction_StateMutability_VIEW:
|
||||||
|
return SolFunctionStateMutability::VIEW;
|
||||||
|
case ContractFunction_StateMutability_PAYABLE:
|
||||||
|
return SolFunctionStateMutability::PAYABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SolLibraryFunctionStateMutability mutabilityConverter(LibraryFunction_StateMutability _mut)
|
||||||
|
{
|
||||||
|
switch (_mut)
|
||||||
|
{
|
||||||
|
case LibraryFunction_StateMutability_PURE:
|
||||||
|
return SolLibraryFunctionStateMutability::PURE;
|
||||||
|
case LibraryFunction_StateMutability_VIEW:
|
||||||
|
return SolLibraryFunctionStateMutability::VIEW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SolFunctionVisibility visibilityConverter(ContractFunction_Visibility _vis)
|
||||||
|
{
|
||||||
|
switch (_vis)
|
||||||
|
{
|
||||||
|
case ContractFunction_Visibility_PUBLIC:
|
||||||
|
return SolFunctionVisibility::PUBLIC;
|
||||||
|
case ContractFunction_Visibility_PRIVATE:
|
||||||
|
return SolFunctionVisibility::PRIVATE;
|
||||||
|
case ContractFunction_Visibility_EXTERNAL:
|
||||||
|
return SolFunctionVisibility::EXTERNAL;
|
||||||
|
case ContractFunction_Visibility_INTERNAL:
|
||||||
|
return SolFunctionVisibility::INTERNAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SolFunctionVisibility visibilityConverter(LibraryFunction_Visibility _vis)
|
||||||
|
{
|
||||||
|
switch (_vis)
|
||||||
|
{
|
||||||
|
case LibraryFunction_Visibility_PUBLIC:
|
||||||
|
return SolFunctionVisibility::PUBLIC;
|
||||||
|
case LibraryFunction_Visibility_PRIVATE:
|
||||||
|
return SolFunctionVisibility::PRIVATE;
|
||||||
|
case LibraryFunction_Visibility_EXTERNAL:
|
||||||
|
return SolFunctionVisibility::EXTERNAL;
|
||||||
|
case LibraryFunction_Visibility_INTERNAL:
|
||||||
|
return SolFunctionVisibility::INTERNAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string functionVisibility(SolFunctionVisibility _vis)
|
||||||
|
{
|
||||||
|
switch (_vis)
|
||||||
|
{
|
||||||
|
case SolFunctionVisibility::PUBLIC:
|
||||||
|
return "public";
|
||||||
|
case SolFunctionVisibility::PRIVATE:
|
||||||
|
return "private";
|
||||||
|
case SolFunctionVisibility::EXTERNAL:
|
||||||
|
return "external";
|
||||||
|
case SolFunctionVisibility::INTERNAL:
|
||||||
|
return "internal";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string functionMutability(SolFunctionStateMutability _mut)
|
||||||
|
{
|
||||||
|
switch (_mut)
|
||||||
|
{
|
||||||
|
case SolFunctionStateMutability::PURE:
|
||||||
|
return "pure";
|
||||||
|
case SolFunctionStateMutability::VIEW:
|
||||||
|
return "view";
|
||||||
|
case SolFunctionStateMutability::PAYABLE:
|
||||||
|
return "payable";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string libraryFunctionMutability(SolLibraryFunctionStateMutability _mut)
|
||||||
|
{
|
||||||
|
switch (_mut)
|
||||||
|
{
|
||||||
|
case SolLibraryFunctionStateMutability::PURE:
|
||||||
|
return "pure";
|
||||||
|
case SolLibraryFunctionStateMutability::VIEW:
|
||||||
|
return "view";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SolInterfaceFunction::SolInterfaceFunction(
|
||||||
|
std::string _functionName,
|
||||||
|
SolFunctionStateMutability _mutability,
|
||||||
|
bool _override
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_functionName = _functionName;
|
||||||
|
m_mutability = _mutability;
|
||||||
|
m_override = _override;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SolInterfaceFunction::operator==(SolInterfaceFunction const& _rhs) const
|
||||||
|
{
|
||||||
|
// TODO: Change this once we permit arbitrary function parameter types
|
||||||
|
return name() == _rhs.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SolInterfaceFunction::operator!=(SolInterfaceFunction const& _rhs) const
|
||||||
|
{
|
||||||
|
// TODO: Change this once we permit arbitrary function parameter types
|
||||||
|
return name() != _rhs.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
string SolInterfaceFunction::str() const
|
||||||
|
{
|
||||||
|
string bodyStr = Whiskers(R"(
|
||||||
|
{
|
||||||
|
return <uint>;
|
||||||
|
})")
|
||||||
|
("uint", "0")
|
||||||
|
.render();
|
||||||
|
|
||||||
|
return Whiskers(R"(
|
||||||
|
function <functionName>() external <stateMutability><?isOverride> override</isOverride>
|
||||||
|
<?isVirtual> virtual</isVirtual> returns (uint)<?isImplemented><body><!isImplemented>;</isImplemented>
|
||||||
|
)")
|
||||||
|
("functionName", name())
|
||||||
|
("stateMutability", functionMutability(mutability()))
|
||||||
|
("isOverride", override())
|
||||||
|
("isVirtual", isVirtual())
|
||||||
|
("isImplemented", implement())
|
||||||
|
("body", bodyStr)
|
||||||
|
.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
SolContractFunction::SolContractFunction(
|
||||||
|
ContractFunction const& _function,
|
||||||
|
std::string _contractName,
|
||||||
|
std::string _functionName,
|
||||||
|
std::string _returnValue
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_contractName = _contractName;
|
||||||
|
m_functionName = _functionName;
|
||||||
|
m_visibility = visibilityConverter(_function.vis());
|
||||||
|
m_mutability = mutabilityConverter(_function.mut());
|
||||||
|
m_virtual = _function.virtualfunc();
|
||||||
|
m_returnValue = _returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SolContractFunction::operator==(SolContractFunction const& _rhs) const
|
||||||
|
{
|
||||||
|
return this->m_visibility == _rhs.m_visibility && this->m_mutability == _rhs.m_mutability;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SolContractFunction::operator!=(SolContractFunction const& _rhs) const
|
||||||
|
{
|
||||||
|
return this->m_visibility != _rhs.m_visibility || this->m_mutability != _rhs.m_mutability;
|
||||||
|
}
|
||||||
|
|
||||||
|
string SolContractFunction::str() const
|
||||||
|
{
|
||||||
|
string bodyStr = Whiskers(R"(
|
||||||
|
{
|
||||||
|
return <uint>;
|
||||||
|
})")
|
||||||
|
("uint", returnValue())
|
||||||
|
.render();
|
||||||
|
|
||||||
|
return Whiskers(R"(
|
||||||
|
function <functionName>()<?isOverride> override</isOverride>
|
||||||
|
<?isVirtual> virtual</isVirtual> <visibility> <stateMutability>
|
||||||
|
returns (uint)<?isImplemented><body><!isImplemented>;</isImplemented>)")
|
||||||
|
("functionName", name())
|
||||||
|
("isVirtual", isVirtual())
|
||||||
|
("isOverride", "_override")
|
||||||
|
("visibility", functionVisibility(visibility()))
|
||||||
|
("stateMutability", functionMutability(mutability()))
|
||||||
|
("body", bodyStr)
|
||||||
|
("isImplemented", "_implement")
|
||||||
|
.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
SolLibraryFunction::SolLibraryFunction(
|
||||||
|
LibraryFunction const& _function,
|
||||||
|
std::string _libraryName,
|
||||||
|
std::string _functionName,
|
||||||
|
std::string _returnValue
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_libraryName = _libraryName;
|
||||||
|
m_functionName = _functionName;
|
||||||
|
m_visibility = visibilityConverter(_function.vis());
|
||||||
|
m_mutability = mutabilityConverter(_function.mut());
|
||||||
|
m_returnValue = _returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string SolLibraryFunction::str() const
|
||||||
|
{
|
||||||
|
string bodyStr = Whiskers(R"(
|
||||||
|
{
|
||||||
|
return <uint>;
|
||||||
|
})")
|
||||||
|
("uint", returnValue())
|
||||||
|
.render();
|
||||||
|
|
||||||
|
return Whiskers(R"(
|
||||||
|
function <functionName>(uint) <visibility> <stateMutability> returns (uint)<body>)")
|
||||||
|
("functionName", name())
|
||||||
|
("visibility", functionVisibility(visibility()))
|
||||||
|
("stateMutability", libraryFunctionMutability(mutability()))
|
||||||
|
("body", bodyStr)
|
||||||
|
.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
SolBaseContract::SolBaseContract(ProtoBaseContract _base, string _name, shared_ptr<SolRandomNumGenerator> _prng)
|
||||||
|
{
|
||||||
|
if (auto c = get<Contract const*>(_base))
|
||||||
|
m_base.push_back(
|
||||||
|
make_shared<SolContract>(SolContract(*c, _name, _prng))
|
||||||
|
);
|
||||||
|
else if (auto i = get<Interface const*>(_base))
|
||||||
|
m_base.push_back(
|
||||||
|
make_shared<SolInterface>(SolInterface(*i, _name, _prng))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SolInterface::overrideHelper(
|
||||||
|
shared_ptr<SolInterfaceFunction> _function,
|
||||||
|
shared_ptr<SolInterface> _base
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto functionName = _function->name();
|
||||||
|
auto mutability = _function->mutability();
|
||||||
|
// Check if two or more bases define this function
|
||||||
|
bool multipleOverride = false;
|
||||||
|
// If function has already been overridden, add
|
||||||
|
// new base to list of overridden bases
|
||||||
|
for (auto &m: m_overrideMap)
|
||||||
|
{
|
||||||
|
// Must override if two or more bases define the
|
||||||
|
// same function
|
||||||
|
if (m.first->operator==(*_function))
|
||||||
|
{
|
||||||
|
// Report error if state mutability of identically
|
||||||
|
// named functions differ
|
||||||
|
if (m.first->mutability() != _function->mutability())
|
||||||
|
assertThrow(
|
||||||
|
false,
|
||||||
|
langutil::FuzzerError,
|
||||||
|
"Input specifies multiple function overrides with identical names"
|
||||||
|
" and parameter types but different mutability."
|
||||||
|
);
|
||||||
|
// Add new base to list of overridden bases
|
||||||
|
m_overrideMap[m.first].push_back(_base);
|
||||||
|
multipleOverride = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If function has not been overridden, add new override
|
||||||
|
if (!multipleOverride)
|
||||||
|
m_overrideMap.insert(
|
||||||
|
pair(
|
||||||
|
make_shared<SolInterfaceFunction>(
|
||||||
|
SolInterfaceFunction(
|
||||||
|
functionName,
|
||||||
|
mutability,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
),
|
||||||
|
vector<shared_ptr<SolInterface>>{_base}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SolInterface::addOverrides()
|
||||||
|
{
|
||||||
|
for (auto &base: m_baseInterfaces)
|
||||||
|
{
|
||||||
|
// Override base interface functions
|
||||||
|
for (auto &f: base->m_interfaceFunctions)
|
||||||
|
overrideHelper(f, base);
|
||||||
|
// Override base interface functions that are themselves overrides
|
||||||
|
for (auto &e: base->m_overrideMap)
|
||||||
|
overrideHelper(e.first, base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SolInterface::addBases(Interface const& _interface)
|
||||||
|
{
|
||||||
|
for (auto &b: _interface.bases())
|
||||||
|
{
|
||||||
|
auto base = make_shared<SolInterface>(SolInterface(b, newBaseName(), m_prng));
|
||||||
|
m_baseInterfaces.push_back(base);
|
||||||
|
cout << "Added " << base->name() << " as base" << endl;
|
||||||
|
// Worst case, we override all base functions so we
|
||||||
|
// increment derived contract's function index by
|
||||||
|
// this amount.
|
||||||
|
m_functionIndex += base->functionIndex();
|
||||||
|
m_lastBaseName = base->lastBaseName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SolInterface::addFunctions(Interface const& _interface)
|
||||||
|
{
|
||||||
|
for (auto &f: _interface.funcdef())
|
||||||
|
m_interfaceFunctions.push_back(
|
||||||
|
make_shared<SolInterfaceFunction>(
|
||||||
|
SolInterfaceFunction(
|
||||||
|
newFunctionName(),
|
||||||
|
mutabilityConverter(f.mut())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SolInterface::SolInterface(Interface const& _interface, string _name, shared_ptr<SolRandomNumGenerator> _prng)
|
||||||
|
{
|
||||||
|
cout << "Constructing " << _name << endl;
|
||||||
|
m_prng = _prng;
|
||||||
|
m_interfaceName = _name;
|
||||||
|
m_lastBaseName = m_interfaceName;
|
||||||
|
addBases(_interface);
|
||||||
|
addOverrides();
|
||||||
|
addFunctions(_interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
string SolInterface::baseNames() const
|
||||||
|
{
|
||||||
|
ostringstream bases;
|
||||||
|
string separator{};
|
||||||
|
for (auto &b: m_baseInterfaces)
|
||||||
|
{
|
||||||
|
bases << separator << b->name();
|
||||||
|
if (separator.empty())
|
||||||
|
separator = ", ";
|
||||||
|
}
|
||||||
|
return bases.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
string SolInterface::baseInterfaceStr() const
|
||||||
|
{
|
||||||
|
ostringstream baseInterfaces;
|
||||||
|
for (auto &b: m_baseInterfaces)
|
||||||
|
baseInterfaces << b->str();
|
||||||
|
|
||||||
|
return baseInterfaces.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
string SolInterface::overrideStr() const
|
||||||
|
{
|
||||||
|
ostringstream overriddenFunctions;
|
||||||
|
for (auto &f: m_overrideMap)
|
||||||
|
{
|
||||||
|
ostringstream overriddenBaseNames;
|
||||||
|
if (f.second.size() > 1)
|
||||||
|
{
|
||||||
|
string sep{};
|
||||||
|
for (auto &b: f.second)
|
||||||
|
{
|
||||||
|
overriddenBaseNames << Whiskers(R"(<sep><name>)")
|
||||||
|
("sep", sep)
|
||||||
|
("name", b->name())
|
||||||
|
.render();
|
||||||
|
if (sep.empty())
|
||||||
|
sep = ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overriddenFunctions << Whiskers(R"(
|
||||||
|
function <functionName>() external <stateMutability> override<?multiple>(<baseNames>)</multiple> returns (uint);)")
|
||||||
|
("functionName", f.first->name())
|
||||||
|
("stateMutability", functionMutability(f.first->mutability()))
|
||||||
|
("multiple", f.second.size() > 1)
|
||||||
|
("baseNames", overriddenBaseNames.str())
|
||||||
|
.render();
|
||||||
|
}
|
||||||
|
return overriddenFunctions.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
string SolInterface::str() const
|
||||||
|
{
|
||||||
|
ostringstream functions;
|
||||||
|
ostringstream bases;
|
||||||
|
|
||||||
|
// Print overridden functions
|
||||||
|
functions << overrideStr();
|
||||||
|
// Print non-overridden functions
|
||||||
|
for (auto &f: m_interfaceFunctions)
|
||||||
|
functions << f->str();
|
||||||
|
|
||||||
|
for (auto &b: m_baseInterfaces)
|
||||||
|
bases << b->str();
|
||||||
|
|
||||||
|
return Whiskers(R"(
|
||||||
|
<bases>
|
||||||
|
interface <programName><?inheritance> is <baseNames></inheritance> {
|
||||||
|
<functionDefs>
|
||||||
|
})")
|
||||||
|
("bases", bases.str())
|
||||||
|
("programName", name())
|
||||||
|
("inheritance", m_baseInterfaces.size() > 0)
|
||||||
|
("baseNames", baseNames())
|
||||||
|
("functionDefs", functions.str())
|
||||||
|
.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
SolContract::SolContract(Contract const& _contract, std::string _name, shared_ptr<SolRandomNumGenerator> _prng)
|
||||||
|
{
|
||||||
|
m_prng = _prng;
|
||||||
|
m_contractName = _name;
|
||||||
|
m_abstract = _contract.abstract();
|
||||||
|
for (auto &f: _contract.funcdef())
|
||||||
|
m_contractFunctions.push_back(
|
||||||
|
make_unique<SolContractFunction>(
|
||||||
|
SolContractFunction(
|
||||||
|
f,
|
||||||
|
m_contractName,
|
||||||
|
newFunctionName(),
|
||||||
|
newReturnValue()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
for (auto &b: _contract.bases())
|
||||||
|
{
|
||||||
|
switch (b.contract_or_interface_oneof_case())
|
||||||
|
{
|
||||||
|
case ContractOrInterface::kC:
|
||||||
|
m_baseContracts.push_back(
|
||||||
|
make_unique<SolBaseContract>(
|
||||||
|
SolBaseContract(&b.c(), newContractBaseName(), m_prng)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case ContractOrInterface::kI:
|
||||||
|
m_baseContracts.push_back(
|
||||||
|
make_unique<SolBaseContract>(
|
||||||
|
SolBaseContract(&b.i(), newInterfaceBaseName(), m_prng)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case ContractOrInterface::CONTRACT_OR_INTERFACE_ONEOF_NOT_SET:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SolLibrary::addFunction(LibraryFunction const& _function)
|
||||||
|
{
|
||||||
|
// Register function name and return value
|
||||||
|
string functionName = newFunctionName();
|
||||||
|
string outputStr = newReturnValue();
|
||||||
|
|
||||||
|
SolFunctionVisibility visibility = visibilityConverter(_function.vis());
|
||||||
|
|
||||||
|
if (visibility == SolFunctionVisibility::PUBLIC || visibility == SolFunctionVisibility::EXTERNAL)
|
||||||
|
{
|
||||||
|
solAssert(!m_publicFunctionMap.count(functionName), "Sol proto adapter: Duplicate library function");
|
||||||
|
m_publicFunctionMap.insert(pair(functionName, outputStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and add function to library
|
||||||
|
m_functions.push_back(
|
||||||
|
make_unique<SolLibraryFunction>(
|
||||||
|
SolLibraryFunction(_function,
|
||||||
|
name(),
|
||||||
|
functionName,
|
||||||
|
outputStr
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SolLibrary::SolLibrary(Library const& _library, string _name)
|
||||||
|
{
|
||||||
|
m_libraryName = _name;
|
||||||
|
for (LibraryFunction const& f: _library.funcdef())
|
||||||
|
addFunction(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
string SolLibrary::str() const
|
||||||
|
{
|
||||||
|
ostringstream functions;
|
||||||
|
|
||||||
|
for (auto &f: m_functions)
|
||||||
|
functions << f->str();
|
||||||
|
|
||||||
|
return Whiskers(R"(
|
||||||
|
library <name> {
|
||||||
|
<functions>
|
||||||
|
})")
|
||||||
|
("name", name())
|
||||||
|
("functions", functions.str())
|
||||||
|
.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SolLibrary::validTest() const
|
||||||
|
{
|
||||||
|
return m_publicFunctionMap.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pair<string, string> SolLibrary::pseudoRandomTest(unsigned _randomIdx)
|
||||||
|
{
|
||||||
|
solAssert(m_publicFunctionMap.size() > 0, "Sol proto adaptor: Empty library map");
|
||||||
|
string chosenFunction;
|
||||||
|
unsigned numFunctions = m_publicFunctionMap.size();
|
||||||
|
unsigned functionIndex = _randomIdx % numFunctions;
|
||||||
|
unsigned mapIdx = 0;
|
||||||
|
for (auto &e: m_publicFunctionMap)
|
||||||
|
{
|
||||||
|
if (functionIndex == mapIdx)
|
||||||
|
chosenFunction = e.first;
|
||||||
|
mapIdx++;
|
||||||
|
}
|
||||||
|
solAssert(m_publicFunctionMap.count(chosenFunction), "Sol proto adaptor: Invalid library function chosen");
|
||||||
|
return pair(chosenFunction, m_publicFunctionMap[chosenFunction]);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFunctionOverride::CFunctionOverrideType CFunctionOverride::functionType() const
|
||||||
|
{
|
||||||
|
if (holds_alternative<unique_ptr<SolContractFunction const>>(m_function.second))
|
||||||
|
return CFunctionOverrideType::CONTRACT;
|
||||||
|
solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
|
||||||
|
return CFunctionOverrideType::INTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
string CFunctionOverride::name() const
|
||||||
|
{
|
||||||
|
if (holds_alternative<unique_ptr<SolContractFunction const>>(m_function.second))
|
||||||
|
return get<unique_ptr<SolContractFunction const>>(m_function.second)->name();
|
||||||
|
solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
|
||||||
|
return get<unique_ptr<SolInterfaceFunction const>>(m_function.second)->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFunctionOverride::interfaceFunction() const
|
||||||
|
{
|
||||||
|
return functionType() == CFunctionOverrideType::INTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFunctionOverride::contractFunction() const
|
||||||
|
{
|
||||||
|
return functionType() == CFunctionOverrideType::CONTRACT;
|
||||||
|
}
|
||||||
|
|
||||||
|
SolFunctionVisibility CFunctionOverride::visibility() const
|
||||||
|
{
|
||||||
|
if (contractFunction())
|
||||||
|
return get<unique_ptr<SolContractFunction const>>(m_function.second)->visibility();
|
||||||
|
solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
|
||||||
|
return SolFunctionVisibility::EXTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SolFunctionStateMutability CFunctionOverride::mutability() const
|
||||||
|
{
|
||||||
|
if (contractFunction())
|
||||||
|
return get<unique_ptr<SolContractFunction const>>(m_function.second)->mutability();
|
||||||
|
solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
|
||||||
|
return get<unique_ptr<SolInterfaceFunction const>>(m_function.second)->mutability();
|
||||||
|
}
|
||||||
|
|
||||||
|
string CFunctionOverride::str() const
|
||||||
|
{
|
||||||
|
string bodyStr = Whiskers(R"(
|
||||||
|
{
|
||||||
|
return <uint>;
|
||||||
|
})")
|
||||||
|
("uint", returnValue())
|
||||||
|
.render();
|
||||||
|
|
||||||
|
return Whiskers(R"(
|
||||||
|
function <functionName>() override <?isVirtual> virtual</isVirtual> <visibility> <stateMutability>
|
||||||
|
returns (uint)<?isImplemented><body><!isImplemented>;</isImplemented>)")
|
||||||
|
("functionName", name())
|
||||||
|
("isVirtual", virtualized() || !implemented())
|
||||||
|
("visibility", functionVisibility(visibility()))
|
||||||
|
("stateMutability", functionMutability(mutability()))
|
||||||
|
("body", bodyStr)
|
||||||
|
("isImplemented", implemented())
|
||||||
|
.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
//string CFunctionOverride::commaSeparatedBaseNames()
|
||||||
|
//{
|
||||||
|
// ostringstream baseNames;
|
||||||
|
// string separator{};
|
||||||
|
// for (auto &override: m_function)
|
||||||
|
// {
|
||||||
|
// auto base = override.first;
|
||||||
|
// string baseName;
|
||||||
|
// if (auto b = get<SolInterface const*>(base))
|
||||||
|
// baseName = b->name();
|
||||||
|
// else
|
||||||
|
// baseName = get<SolContract const*>(base)->name();
|
||||||
|
//
|
||||||
|
// baseNames << Whiskers(R"(<sep><base>)")
|
||||||
|
// ("sep", separator)
|
||||||
|
// ("base", baseName)
|
||||||
|
// .render();
|
||||||
|
// if (separator.empty())
|
||||||
|
// separator = ", ";
|
||||||
|
// }
|
||||||
|
// return baseNames.str();
|
||||||
|
//}
|
||||||
|
|
||||||
|
//string CFunctionOverride::baseName() const
|
||||||
|
//{
|
||||||
|
// auto base = m_function.first;
|
||||||
|
// if (contractFunction())
|
||||||
|
// return get<shared_ptr<SolContract const>>(base)->name();
|
||||||
|
// solAssert(interfaceFunction(), "Sol proto fuzzer: Invalid override function type");
|
||||||
|
// return get<shared_ptr<SolInterface const>>(base)->name();
|
||||||
|
//}
|
520
test/tools/ossfuzz/SolProtoAdaptor.h
Normal file
520
test/tools/ossfuzz/SolProtoAdaptor.h
Normal file
@ -0,0 +1,520 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <test/tools/ossfuzz/protoToSol.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
namespace solidity::test::solprotofuzzer::adaptor
|
||||||
|
{
|
||||||
|
/// Solidity contract abstraction class
|
||||||
|
struct SolContract;
|
||||||
|
/// Solidity interface abstraction class
|
||||||
|
struct SolInterface;
|
||||||
|
/// Solidity library abstraction class
|
||||||
|
struct SolLibrary;
|
||||||
|
/// Solidity interface function abstraction class
|
||||||
|
struct SolInterfaceFunction;
|
||||||
|
/// Solidity contract function abstraction class
|
||||||
|
struct SolContractFunction;
|
||||||
|
/// Solidity library function abstraction class
|
||||||
|
struct SolLibraryFunction;
|
||||||
|
/// Solidity contract function override abstraction class
|
||||||
|
struct CFunctionOverride;
|
||||||
|
/// Solidity interface function override abstraction class
|
||||||
|
struct IFunctionOverride;
|
||||||
|
|
||||||
|
/// Type that defines a contract function override as a variant of interface or
|
||||||
|
/// contract function types.
|
||||||
|
using OverrideFunction = std::variant<std::unique_ptr<SolInterfaceFunction const>, std::unique_ptr<SolContractFunction const>>;
|
||||||
|
/// Type that defines a list of base contracts as a list of variants of interface or
|
||||||
|
/// contract types.
|
||||||
|
using BaseContracts = std::vector<std::variant<std::shared_ptr<SolInterface const>, std::shared_ptr<SolContract const>>>;
|
||||||
|
/// Type that defines a contract function override as a pair of base contracts
|
||||||
|
/// and its (their) function.
|
||||||
|
using OverrideCFunction = std::pair<BaseContracts, OverrideFunction>;
|
||||||
|
/// Type that defines an interface function override as a pair of interface
|
||||||
|
/// and its function.
|
||||||
|
using OverrideIFunction = std::pair<std::vector<std::shared_ptr<SolInterface const>>, std::unique_ptr<SolInterfaceFunction const>>;
|
||||||
|
/// Type that defines a map of interface overrides
|
||||||
|
using InterfaceOverrideMap = std::map<std::shared_ptr<SolInterfaceFunction>, std::vector<std::shared_ptr<SolInterface>>>;
|
||||||
|
/// Type that defines an interface function as either a vanilla interface function
|
||||||
|
/// or an override function.
|
||||||
|
using IFunction = std::variant<std::unique_ptr<SolInterfaceFunction>, OverrideIFunction>;
|
||||||
|
/// Type that defines a contract function as either a vanilla contract function
|
||||||
|
/// or an override function.
|
||||||
|
using CFunction = std::variant<std::unique_ptr<SolContractFunction>, OverrideCFunction>;
|
||||||
|
/// Variant type that points to one of contract, interface protobuf messages
|
||||||
|
using ProtoBaseContract = std::variant<Contract const*, Interface const*>;
|
||||||
|
|
||||||
|
enum class SolFunctionVisibility
|
||||||
|
{
|
||||||
|
PUBLIC,
|
||||||
|
PRIVATE,
|
||||||
|
INTERNAL,
|
||||||
|
EXTERNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SolFunctionStateMutability
|
||||||
|
{
|
||||||
|
PURE,
|
||||||
|
VIEW,
|
||||||
|
PAYABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SolLibraryFunctionStateMutability
|
||||||
|
{
|
||||||
|
PURE,
|
||||||
|
VIEW
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SolInterfaceFunction
|
||||||
|
{
|
||||||
|
SolInterfaceFunction(
|
||||||
|
std::string _functionName,
|
||||||
|
SolFunctionStateMutability _mutability,
|
||||||
|
bool _override = false
|
||||||
|
);
|
||||||
|
bool operator==(SolInterfaceFunction const& _rhs) const;
|
||||||
|
bool operator!=(SolInterfaceFunction const& _rhs) const;
|
||||||
|
std::string str() const;
|
||||||
|
|
||||||
|
std::string name() const
|
||||||
|
{
|
||||||
|
return m_functionName;
|
||||||
|
}
|
||||||
|
SolFunctionStateMutability mutability() const
|
||||||
|
{
|
||||||
|
return m_mutability;
|
||||||
|
}
|
||||||
|
bool override() const
|
||||||
|
{
|
||||||
|
return m_override;
|
||||||
|
}
|
||||||
|
bool isVirtual() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool implement() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string m_functionName;
|
||||||
|
SolFunctionStateMutability m_mutability = SolFunctionStateMutability::PURE;
|
||||||
|
bool m_override = false;
|
||||||
|
bool m_virtual = false;
|
||||||
|
bool m_implement = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SolContractFunction
|
||||||
|
{
|
||||||
|
SolContractFunction(
|
||||||
|
ContractFunction const& _function,
|
||||||
|
std::string _contractName,
|
||||||
|
std::string _functionName,
|
||||||
|
std::string _returnValue
|
||||||
|
);
|
||||||
|
bool operator==(SolContractFunction const& _rhs) const;
|
||||||
|
bool operator!=(SolContractFunction const& _rhs) const;
|
||||||
|
std::string str() const;
|
||||||
|
|
||||||
|
std::string name() const
|
||||||
|
{
|
||||||
|
return m_functionName;
|
||||||
|
}
|
||||||
|
std::string contractName() const
|
||||||
|
{
|
||||||
|
return m_contractName;
|
||||||
|
}
|
||||||
|
bool isVirtual() const
|
||||||
|
{
|
||||||
|
return m_virtual;
|
||||||
|
}
|
||||||
|
std::string returnValue() const
|
||||||
|
{
|
||||||
|
return m_returnValue;
|
||||||
|
}
|
||||||
|
SolFunctionVisibility visibility() const
|
||||||
|
{
|
||||||
|
return m_visibility;
|
||||||
|
}
|
||||||
|
SolFunctionStateMutability mutability() const
|
||||||
|
{
|
||||||
|
return m_mutability;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string m_contractName;
|
||||||
|
std::string m_functionName;
|
||||||
|
SolFunctionVisibility m_visibility = SolFunctionVisibility::PUBLIC;
|
||||||
|
SolFunctionStateMutability m_mutability = SolFunctionStateMutability::PURE;
|
||||||
|
bool m_virtual = false;
|
||||||
|
std::string m_returnValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SolLibraryFunction
|
||||||
|
{
|
||||||
|
SolLibraryFunction(
|
||||||
|
LibraryFunction const& _function,
|
||||||
|
std::string _libraryName,
|
||||||
|
std::string _functionName,
|
||||||
|
std::string _returnValue
|
||||||
|
);
|
||||||
|
std::string str() const;
|
||||||
|
|
||||||
|
std::string name() const
|
||||||
|
{
|
||||||
|
return m_functionName;
|
||||||
|
}
|
||||||
|
std::string libraryName() const
|
||||||
|
{
|
||||||
|
return m_libraryName;
|
||||||
|
}
|
||||||
|
std::string returnValue() const
|
||||||
|
{
|
||||||
|
return m_returnValue;
|
||||||
|
}
|
||||||
|
SolFunctionVisibility visibility() const
|
||||||
|
{
|
||||||
|
return m_visibility;
|
||||||
|
}
|
||||||
|
SolLibraryFunctionStateMutability mutability() const
|
||||||
|
{
|
||||||
|
return m_mutability;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string m_libraryName;
|
||||||
|
std::string m_functionName;
|
||||||
|
SolFunctionVisibility m_visibility = SolFunctionVisibility::PUBLIC;
|
||||||
|
SolLibraryFunctionStateMutability m_mutability = SolLibraryFunctionStateMutability::PURE;
|
||||||
|
std::string m_returnValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SolLibrary
|
||||||
|
{
|
||||||
|
SolLibrary(Library const& _library, std::string _name);
|
||||||
|
std::vector<std::unique_ptr<SolLibraryFunction>> m_functions;
|
||||||
|
/// Maps publicly exposed function name to expected output
|
||||||
|
std::map<std::string, std::string> m_publicFunctionMap;
|
||||||
|
|
||||||
|
void addFunction(LibraryFunction const& _function);
|
||||||
|
|
||||||
|
bool validTest() const;
|
||||||
|
|
||||||
|
/// Returns a pair of function name and expected output
|
||||||
|
/// that is pseudo randomly chosen from the list of all
|
||||||
|
/// library functions.
|
||||||
|
/// @param _randomIdx A pseudo randomly generated number that is
|
||||||
|
/// used to index the list of all library functions.
|
||||||
|
std::pair<std::string, std::string> pseudoRandomTest(unsigned _randomIdx);
|
||||||
|
|
||||||
|
std::string str() const;
|
||||||
|
|
||||||
|
std::string name() const
|
||||||
|
{
|
||||||
|
return m_libraryName;
|
||||||
|
}
|
||||||
|
std::string newFunctionName()
|
||||||
|
{
|
||||||
|
return "f" + std::to_string(m_functionIndex++);
|
||||||
|
}
|
||||||
|
std::string newReturnValue()
|
||||||
|
{
|
||||||
|
return std::to_string(m_returnValue++);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string m_libraryName;
|
||||||
|
unsigned m_functionIndex = 0;
|
||||||
|
unsigned m_returnValue = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SolBaseContract
|
||||||
|
{
|
||||||
|
SolBaseContract(ProtoBaseContract _base, std::string _name, std::shared_ptr<SolRandomNumGenerator> _prng);
|
||||||
|
|
||||||
|
BaseContracts m_base;
|
||||||
|
std::string m_baseName;
|
||||||
|
std::shared_ptr<SolRandomNumGenerator> m_prng;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SolContract
|
||||||
|
{
|
||||||
|
SolContract(Contract const& _contract, std::string _name, std::shared_ptr<SolRandomNumGenerator> _prng);
|
||||||
|
|
||||||
|
std::string str() const;
|
||||||
|
|
||||||
|
unsigned randomNumber()
|
||||||
|
{
|
||||||
|
return m_prng->operator()();
|
||||||
|
}
|
||||||
|
std::string name() const
|
||||||
|
{
|
||||||
|
return m_contractName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool abstract() const
|
||||||
|
{
|
||||||
|
return m_abstract;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string newFunctionName()
|
||||||
|
{
|
||||||
|
return "f" + std::to_string(m_functionIndex++);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string newContractBaseName()
|
||||||
|
{
|
||||||
|
return name() + "B" + std::to_string(m_baseIndex++);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string newInterfaceBaseName()
|
||||||
|
{
|
||||||
|
return "IB" + std::to_string(m_baseIndex++);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string newReturnValue()
|
||||||
|
{
|
||||||
|
return std::to_string(m_returnValue++);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string m_contractName;
|
||||||
|
bool m_abstract = false;
|
||||||
|
unsigned m_baseIndex = 0;
|
||||||
|
unsigned m_functionIndex = 0;
|
||||||
|
unsigned m_returnValue = 0;
|
||||||
|
std::vector<std::unique_ptr<SolContractFunction>> m_contractFunctions;
|
||||||
|
std::vector<std::unique_ptr<SolBaseContract>> m_baseContracts;
|
||||||
|
std::vector<std::unique_ptr<CFunctionOverride>> m_overriddenFunctions;
|
||||||
|
std::shared_ptr<SolRandomNumGenerator> m_prng;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SolInterface
|
||||||
|
{
|
||||||
|
SolInterface(
|
||||||
|
Interface const& _interface,
|
||||||
|
std::string _interfaceName,
|
||||||
|
std::shared_ptr<SolRandomNumGenerator> _prng
|
||||||
|
);
|
||||||
|
|
||||||
|
std::string name() const
|
||||||
|
{
|
||||||
|
return m_interfaceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned randomNumber() const
|
||||||
|
{
|
||||||
|
return m_prng->operator()();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool coinFlip() const
|
||||||
|
{
|
||||||
|
return randomNumber() % 2 == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string newFunctionName()
|
||||||
|
{
|
||||||
|
return "f" + std::to_string(m_functionIndex++);
|
||||||
|
}
|
||||||
|
void incrementFunctionIndex()
|
||||||
|
{
|
||||||
|
m_functionIndex++;
|
||||||
|
}
|
||||||
|
void resetFunctionIndex()
|
||||||
|
{
|
||||||
|
m_functionIndex = 0;
|
||||||
|
}
|
||||||
|
void setFunctionIndex(unsigned _index)
|
||||||
|
{
|
||||||
|
m_functionIndex = _index;
|
||||||
|
}
|
||||||
|
unsigned functionIndex() const
|
||||||
|
{
|
||||||
|
return m_functionIndex;
|
||||||
|
}
|
||||||
|
std::string newBaseName()
|
||||||
|
{
|
||||||
|
m_lastBaseName += "B";
|
||||||
|
return m_lastBaseName;
|
||||||
|
}
|
||||||
|
std::string lastBaseName()
|
||||||
|
{
|
||||||
|
return m_lastBaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string str() const;
|
||||||
|
std::string overrideStr() const;
|
||||||
|
|
||||||
|
/// Returns the Solidity code for all base interfaces
|
||||||
|
/// inherited by this interface.
|
||||||
|
std::string baseInterfaceStr() const;
|
||||||
|
|
||||||
|
/// Returns comma-space separated names of base interfaces inherited by
|
||||||
|
/// this interface.
|
||||||
|
std::string baseNames() const;
|
||||||
|
|
||||||
|
/// Add base contracts in a depth-first manner
|
||||||
|
void addBases(Interface const& _interface);
|
||||||
|
/// Add functions
|
||||||
|
void addFunctions(Interface const& _interface);
|
||||||
|
/// Add overrides
|
||||||
|
void addOverrides();
|
||||||
|
/// Helper for adding overrides
|
||||||
|
void overrideHelper(
|
||||||
|
std::shared_ptr<SolInterfaceFunction> _function,
|
||||||
|
std::shared_ptr<SolInterface> _interface
|
||||||
|
);
|
||||||
|
|
||||||
|
unsigned m_functionIndex = 0;
|
||||||
|
std::string m_lastBaseName;
|
||||||
|
std::string m_interfaceName;
|
||||||
|
std::vector<std::shared_ptr<SolInterfaceFunction>> m_interfaceFunctions;
|
||||||
|
std::vector<std::shared_ptr<SolInterface>> m_baseInterfaces;
|
||||||
|
InterfaceOverrideMap m_overrideMap;
|
||||||
|
std::shared_ptr<SolRandomNumGenerator> m_prng;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CFunctionOverride
|
||||||
|
{
|
||||||
|
CFunctionOverride(
|
||||||
|
BaseContracts _base,
|
||||||
|
OverrideFunction _function,
|
||||||
|
bool _implemented,
|
||||||
|
bool _virtualized,
|
||||||
|
bool _redeclared,
|
||||||
|
std::string _returnValue
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_function = std::make_pair(_base, std::move(_function));
|
||||||
|
m_implemented = _implemented;
|
||||||
|
m_virtualized = _virtualized;
|
||||||
|
m_redeclared = _redeclared;
|
||||||
|
m_returnValue = _returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class CFunctionOverrideType
|
||||||
|
{
|
||||||
|
INTERFACE,
|
||||||
|
CONTRACT
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string str() const;
|
||||||
|
|
||||||
|
std::string name() const;
|
||||||
|
|
||||||
|
CFunctionOverrideType functionType() const;
|
||||||
|
|
||||||
|
bool interfaceFunction() const;
|
||||||
|
|
||||||
|
bool contractFunction() const;
|
||||||
|
|
||||||
|
SolFunctionVisibility visibility() const;
|
||||||
|
|
||||||
|
SolFunctionStateMutability mutability() const;
|
||||||
|
|
||||||
|
std::string commaSeparatedBaseNames() const;
|
||||||
|
|
||||||
|
std::string baseName() const;
|
||||||
|
|
||||||
|
/// Overridden function
|
||||||
|
OverrideCFunction m_function;
|
||||||
|
/// Flag that is true if overridden function is implemented
|
||||||
|
bool m_implemented = true;
|
||||||
|
/// Flag that is true if overridden function is marked virtual
|
||||||
|
bool m_virtualized = false;
|
||||||
|
/// Flag that is true if overridden function is redeclared but not implemented
|
||||||
|
bool m_redeclared = false;
|
||||||
|
/// The uint value to be returned by the overridden function if it is
|
||||||
|
/// implemented
|
||||||
|
std::string m_returnValue;
|
||||||
|
|
||||||
|
bool implemented() const
|
||||||
|
{
|
||||||
|
return m_implemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool virtualized() const
|
||||||
|
{
|
||||||
|
return m_virtualized;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool redeclared() const
|
||||||
|
{
|
||||||
|
return m_redeclared;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string returnValue() const
|
||||||
|
{
|
||||||
|
return m_returnValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IFunctionOverride
|
||||||
|
{
|
||||||
|
IFunctionOverride(
|
||||||
|
std::vector<std::shared_ptr<SolInterface const>> _base,
|
||||||
|
std::unique_ptr<SolInterfaceFunction const> _function,
|
||||||
|
bool _implement,
|
||||||
|
bool _virtual,
|
||||||
|
bool _redeclare,
|
||||||
|
std::string _returnValue = ""
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_function = std::make_pair(_base, std::move(_function));
|
||||||
|
m_implemented = _implement;
|
||||||
|
m_virtualized = _virtual;
|
||||||
|
m_redeclared = _redeclare;
|
||||||
|
m_returnValue = _returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string str() const;
|
||||||
|
|
||||||
|
bool implemented() const
|
||||||
|
{
|
||||||
|
return m_implemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool virtualized() const
|
||||||
|
{
|
||||||
|
return m_virtualized;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool redeclared() const
|
||||||
|
{
|
||||||
|
return m_redeclared;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string returnValue() const
|
||||||
|
{
|
||||||
|
return m_returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverrideIFunction m_function;
|
||||||
|
/// Flag that is true if overridden function is implemented in derived contract
|
||||||
|
bool m_implemented = false;
|
||||||
|
/// Flag that is true if overridden function implemented in derived contract is
|
||||||
|
/// marked virtual
|
||||||
|
bool m_virtualized = false;
|
||||||
|
/// Flag that is true if overridden function is redeclared but not implemented
|
||||||
|
bool m_redeclared = false;
|
||||||
|
/// The uint value to be returned if the overridden interface function is implemented
|
||||||
|
std::string m_returnValue;
|
||||||
|
};
|
||||||
|
}
|
@ -9,13 +9,16 @@ SolidityCompilationFramework::SolidityCompilationFramework(langutil::EVMVersion
|
|||||||
|
|
||||||
solidity::bytes SolidityCompilationFramework::compileContract(
|
solidity::bytes SolidityCompilationFramework::compileContract(
|
||||||
std::string const& _sourceCode,
|
std::string const& _sourceCode,
|
||||||
std::string const& _contractName
|
std::string const& _contractName,
|
||||||
|
std::map<std::string, solidity::util::h160> const& _libraryAddresses,
|
||||||
|
frontend::OptimiserSettings _optimization
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
std::string sourceCode = _sourceCode;
|
std::string sourceCode = _sourceCode;
|
||||||
m_compiler.setSources({{"", sourceCode}});
|
m_compiler.setSources({{"", sourceCode}});
|
||||||
|
m_compiler.setLibraries(_libraryAddresses);
|
||||||
m_compiler.setEVMVersion(m_evmVersion);
|
m_compiler.setEVMVersion(m_evmVersion);
|
||||||
m_compiler.setOptimiserSettings(m_optimiserSettings);
|
m_compiler.setOptimiserSettings(_optimization);
|
||||||
if (!m_compiler.compile())
|
if (!m_compiler.compile())
|
||||||
{
|
{
|
||||||
langutil::SourceReferenceFormatter formatter(std::cerr);
|
langutil::SourceReferenceFormatter formatter(std::cerr);
|
||||||
|
@ -23,12 +23,13 @@ public:
|
|||||||
}
|
}
|
||||||
bytes compileContract(
|
bytes compileContract(
|
||||||
std::string const& _sourceCode,
|
std::string const& _sourceCode,
|
||||||
std::string const& _contractName = {}
|
std::string const& _contractName,
|
||||||
|
std::map<std::string, solidity::util::h160> const& _libraryAddresses = {},
|
||||||
|
frontend::OptimiserSettings _optimization = frontend::OptimiserSettings::minimal()
|
||||||
);
|
);
|
||||||
protected:
|
protected:
|
||||||
frontend::CompilerStack m_compiler;
|
frontend::CompilerStack m_compiler;
|
||||||
langutil::EVMVersion m_evmVersion;
|
langutil::EVMVersion m_evmVersion;
|
||||||
frontend::OptimiserSettings m_optimiserSettings = frontend::OptimiserSettings::none();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -14,48 +14,29 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <test/tools/ossfuzz/solProto.pb.h>
|
#include <test/tools/ossfuzz/solProto.pb.h>
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
namespace solidity::test::solprotofuzzer
|
namespace solidity::test::solprotofuzzer
|
||||||
{
|
{
|
||||||
struct ProgramInfo
|
struct SolRandomNumGenerator
|
||||||
{
|
{
|
||||||
enum class ProgramType
|
using RandomEngine = std::minstd_rand;
|
||||||
{
|
|
||||||
LIBRARY,
|
|
||||||
CONTRACT,
|
|
||||||
INTERFACE
|
|
||||||
};
|
|
||||||
std::string m_name;
|
|
||||||
std::string m_userDefinedTypes;
|
|
||||||
ProgramType m_programType;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FunctionInfo
|
explicit SolRandomNumGenerator(unsigned _seed): m_random(RandomEngine(_seed)) {}
|
||||||
{
|
|
||||||
enum class FunctionVisibility
|
unsigned operator()()
|
||||||
{
|
{
|
||||||
PUBLIC,
|
return m_random();
|
||||||
PRIVATE,
|
}
|
||||||
INTERNAL,
|
|
||||||
EXTERNAL
|
RandomEngine m_random;
|
||||||
};
|
|
||||||
enum class StateMutability
|
|
||||||
{
|
|
||||||
PURE,
|
|
||||||
VIEW,
|
|
||||||
PAYABLE
|
|
||||||
};
|
|
||||||
std::string m_name;
|
|
||||||
std::string m_params;
|
|
||||||
std::string m_returns;
|
|
||||||
FunctionVisibility m_visibility;
|
|
||||||
StateMutability m_mutability;
|
|
||||||
bool m_override;
|
|
||||||
bool m_virtual;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProtoConverter
|
class ProtoConverter
|
||||||
@ -65,82 +46,155 @@ public:
|
|||||||
ProtoConverter(ProtoConverter const&) = delete;
|
ProtoConverter(ProtoConverter const&) = delete;
|
||||||
ProtoConverter(ProtoConverter&&) = delete;
|
ProtoConverter(ProtoConverter&&) = delete;
|
||||||
std::string protoToSolidity(Program const&);
|
std::string protoToSolidity(Program const&);
|
||||||
private:
|
|
||||||
using CI = std::variant<Contract const*, Interface const*>;
|
|
||||||
|
|
||||||
|
/// @returns true if test calls a library function, false
|
||||||
|
/// otherwise
|
||||||
|
bool libraryTest() const;
|
||||||
|
/// @returns name of the library under test
|
||||||
|
std::string libraryName() const;
|
||||||
|
private:
|
||||||
|
enum MostDerivedProgram {
|
||||||
|
CONTRACT,
|
||||||
|
INTERFACE,
|
||||||
|
LIBRARY
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Variant type that points to one of contract, interface, library protobuf messages
|
||||||
|
using CIL = std::variant<Contract const*, Interface const*, Library const*>;
|
||||||
|
/// Variant type that points to one of contract, interface, library function protobuf
|
||||||
|
/// messages
|
||||||
|
using CILFunc = std::variant<ContractFunction const*, InterfaceFunction const*, LibraryFunction const*>;
|
||||||
|
/// Variant type that points to one of contract, interface protobuf messages
|
||||||
|
using CI = std::variant<Contract const*, Interface const*>;
|
||||||
|
/// Variant type that points to one of contract, interface function protobuf messages
|
||||||
|
using CIFunc = std::variant<ContractFunction const*, InterfaceFunction const*>;
|
||||||
|
/// Tuple of contract or interface function variant and a boolean stating whether
|
||||||
|
/// the function is implemented (true) or not and a second boolean stating whether
|
||||||
|
/// the function is virtual (true) or not.
|
||||||
|
using CITuple = std::tuple<CIFunc, bool, bool>;
|
||||||
|
/// Protobuf message visitors that accept a const reference to a protobuf message
|
||||||
|
/// type and return its solidity translation.
|
||||||
std::string visit(Program const&);
|
std::string visit(Program const&);
|
||||||
|
std::string visit(TestContract const&);
|
||||||
std::string visit(ContractType const&);
|
std::string visit(ContractType const&);
|
||||||
std::string visit(ContractOrInterface const&);
|
std::string visit(ContractOrInterface const&);
|
||||||
std::string visit(Interface const&);
|
std::string visit(Interface const& _interface);
|
||||||
|
/// Visitor for most derived interface messages.
|
||||||
|
/// @param _interface is a const reference to interface protobuf message
|
||||||
|
/// @returns a 3-tuple containing Solidity translation of all base contracts
|
||||||
|
/// this interface derives from, names of all base contracts, and the Solidity
|
||||||
|
/// translation of this interface.
|
||||||
|
std::tuple<std::string, std::string, std::string>
|
||||||
|
visitMostDerivedInterface(Interface const& _interface);
|
||||||
std::string visit(Contract const&);
|
std::string visit(Contract const&);
|
||||||
std::string traverseOverrides(
|
/// Define overrides for most derived interface.
|
||||||
Interface const&,
|
std::string mostDerivedInterfaceOverrides(Interface const& _interface);
|
||||||
bool _isOverride,
|
/// Define overrides for most derived contract.
|
||||||
bool _implement,
|
std::string mostDerivedContractOverrides(Interface const& _interface);
|
||||||
bool _inheritedByContract,
|
std::string traverseOverrides(Contract const&);
|
||||||
bool _isVirtual
|
std::string registerAndVisitFunction(
|
||||||
|
CIL _program,
|
||||||
|
CILFunc _func,
|
||||||
|
unsigned _index,
|
||||||
|
bool _override,
|
||||||
|
bool _virtual,
|
||||||
|
bool _implement
|
||||||
);
|
);
|
||||||
std::string traverseOverrides(
|
std::string overrideFunction(CILFunc _function, bool _virtual, bool _implement);
|
||||||
Contract const&,
|
std::pair<bool, bool> contractFunctionParams(
|
||||||
bool _isAbstract
|
Contract const* _contract,
|
||||||
|
ContractFunction const* _function
|
||||||
);
|
);
|
||||||
|
std::string visit(CILFunc _function, bool _override, bool _virtual, bool _implement);
|
||||||
std::string visit(Library const&);
|
std::string visit(Library const&);
|
||||||
std::pair<std::string, std::string> visit(Block const&);
|
std::string programName(CIL _program);
|
||||||
std::pair<std::string, std::string> visit(Statement const&);
|
std::string createFunctionName(CIL _program, unsigned _index);
|
||||||
std::pair<std::string, std::string> visit(solidity::test::abiv2fuzzer::VarDecl const&, bool _stateVar);
|
std::string functionName(CILFunc _function);
|
||||||
std::pair<std::string, std::string> visit(IfStmt const&);
|
void registerFunctionName(CIL _program, CILFunc _function, unsigned _index);
|
||||||
std::string visit(ForStmt const&);
|
std::tuple<std::string, std::string, std::string> visitProgramHelper(CIL _program);
|
||||||
std::string visit(SwitchStmt const&);
|
bool contractFunctionImplemented(Contract const* _contract, CIFunc _function);
|
||||||
std::string visit(BreakStmt const&);
|
bool contractFunctionVirtual(Contract const* _contract, CIFunc _function);
|
||||||
std::string visit(ContinueStmt const&);
|
std::tuple<bool, bool, bool> mostDerivedContractOverrideParams();
|
||||||
std::string visit(ReturnStmt const&);
|
|
||||||
std::pair<std::string, std::string> visit(DoStmt const&);
|
std::pair<bool, bool> contractFunctionOverrideParams(
|
||||||
std::pair<std::string, std::string> visit(WhileStmt const&);
|
Contract const* _base,
|
||||||
std::string visit(Expression const&);
|
Contract const* _derived,
|
||||||
std::string visit(Literal const&);
|
CIFunc _baseFunc
|
||||||
std::string visit(BinaryOp const&);
|
);
|
||||||
std::string visit(UnaryOp const&);
|
std::tuple<std::string, std::string, std::string> pseudoRandomLibraryTest(unsigned _randomIdx);
|
||||||
std::string visit(VarRef const&);
|
|
||||||
std::tuple<std::string, std::string, std::string> visit(
|
bool emptyLibrary(Library const& _library)
|
||||||
FunctionParamsAndReturns const& _pR,
|
{
|
||||||
bool _isExternal,
|
return _library.funcdef_size() == 0;
|
||||||
std::string _programName
|
}
|
||||||
);
|
bool emptyLibraryTests()
|
||||||
std::string visit(
|
{
|
||||||
InterfaceFunction const&,
|
return m_libraryTests.size() == 0;
|
||||||
unsigned _index,
|
}
|
||||||
bool _isOverride,
|
|
||||||
std::string _programName,
|
void openProgramScope(CIL _program);
|
||||||
bool _implement = false,
|
bool pseudoRandomCoinFlip()
|
||||||
bool _inheritedByContract = false,
|
{
|
||||||
bool _isVirtual = false
|
return m_counter++ % 2 == 0;
|
||||||
);
|
}
|
||||||
std::string visit(LibraryFunction const& _func, unsigned _index, std::string _programName);
|
bool mostDerivedProgramContract()
|
||||||
std::string visit(
|
{
|
||||||
ContractFunction const&,
|
return m_mostDerivedProgram == MostDerivedProgram::CONTRACT;
|
||||||
unsigned _index,
|
}
|
||||||
bool _isOverride,
|
bool mostDerivedProgramInterface()
|
||||||
bool _isAbstractContract,
|
{
|
||||||
bool _isVirtual,
|
return m_mostDerivedProgram == MostDerivedProgram::INTERFACE;
|
||||||
bool _isImplemented,
|
}
|
||||||
std::string _programName
|
bool mostDerivedProgramAbstractContract()
|
||||||
);
|
{
|
||||||
std::tuple<std::string, std::string, std::string> visitContractHelper(CI _cOrI, std::string _programName);
|
return m_mostDerivedAbstractContract;
|
||||||
std::string visit(Modifier const&);
|
}
|
||||||
static std::string functionVisibility(ContractFunction::Visibility _vis);
|
unsigned randomNumber();
|
||||||
static std::string functionVisibility(LibraryFunction::Visibility _vis);
|
|
||||||
static std::string stateMutability(ContractFunction::StateMutability _mut);
|
#if 0
|
||||||
static std::string stateMutability(LibraryFunction::StateMutability _mut);
|
static bool disallowedContractFunction(SolContractFunction const& _contractFunction, bool _isVirtual);
|
||||||
static std::string stateMutability(InterfaceFunction::StateMutability _mut);
|
#endif
|
||||||
static bool disallowedContractFunction(ContractFunction const& _contractFunction, bool _isVirtual);
|
|
||||||
|
|
||||||
unsigned m_numVars = 0;
|
|
||||||
unsigned m_numStructs = 0;
|
|
||||||
unsigned m_numMods = 0;
|
unsigned m_numMods = 0;
|
||||||
unsigned m_numContracts = 0;
|
unsigned m_numPrograms = 0;
|
||||||
bool m_isImplemented = false;
|
unsigned m_counter = 0;
|
||||||
|
bool m_mostDerivedAbstractContract = false;
|
||||||
|
bool m_libraryTest = false;
|
||||||
|
std::shared_ptr<SolRandomNumGenerator> m_randomGen;
|
||||||
|
|
||||||
|
MostDerivedProgram m_mostDerivedProgram = MostDerivedProgram::CONTRACT;
|
||||||
|
/// Map whose key is pointer to protobuf interface message
|
||||||
|
/// and whose value is its contract name
|
||||||
std::map<Interface const*, std::string> m_interfaceNameMap;
|
std::map<Interface const*, std::string> m_interfaceNameMap;
|
||||||
|
/// Map whose key is pointer to protobuf contract message
|
||||||
|
/// and whose value is its contract name
|
||||||
std::map<Contract const*, std::string> m_contractNameMap;
|
std::map<Contract const*, std::string> m_contractNameMap;
|
||||||
|
/// Map whose key is library name and whose value is the
|
||||||
|
/// number of implemented functions in it.
|
||||||
|
std::map<std::string, unsigned> m_libraryFuncMap;
|
||||||
|
/// Map whose key is a const pointer to protobuf contract
|
||||||
|
/// message and whose value is a list of 3-tuples that
|
||||||
|
/// store a const pointer to a protobuf interface or contract
|
||||||
|
/// function belonging to the keyed contract, a boolean flag that is
|
||||||
|
/// true when the function is implemented, false otherwise, and
|
||||||
|
/// a second boolean flag that is true when the function is virtualized
|
||||||
|
/// false otherwise.
|
||||||
|
std::map<Contract const*, std::vector<CITuple>> m_contractFunctionMap;
|
||||||
|
/// Map whose key is a const pointer to protobuf contract, interface or
|
||||||
|
/// library function message type and whose value is the function name
|
||||||
|
/// assigned to it.
|
||||||
|
std::map<CILFunc, std::string> m_functionNameMap;
|
||||||
|
std::map<CIL, std::string> m_programNameMap;
|
||||||
|
/// Map whose key is a const pointer to protobuf contract or interface
|
||||||
|
/// function message type and whose value is a pair of const pointer to
|
||||||
|
/// protobuf contract or interface it belongs to and its declaration
|
||||||
|
/// position (which is an unsigned integer that starts from 0).
|
||||||
|
std::map<CIFunc, std::pair<CI, unsigned>> m_functionProgramMap;
|
||||||
|
|
||||||
|
std::map<CI, std::vector<std::pair<CIFunc, std::string>>> m_programFunctionNameMap;
|
||||||
|
|
||||||
|
std::vector<std::tuple<std::string, std::string, std::string>> m_libraryTests;
|
||||||
|
std::string m_libraryName;
|
||||||
|
|
||||||
static auto constexpr s_interfaceFunctionPrefix = "i";
|
static auto constexpr s_interfaceFunctionPrefix = "i";
|
||||||
static auto constexpr s_libraryFunctionPrefix = "l";
|
static auto constexpr s_libraryFunctionPrefix = "l";
|
||||||
|
@ -17,22 +17,13 @@
|
|||||||
|
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
|
|
||||||
import "abiV2Proto.proto";
|
|
||||||
|
|
||||||
message FunctionParamsAndReturns {
|
|
||||||
repeated solidity.test.abiv2fuzzer.Type params = 1;
|
|
||||||
repeated solidity.test.abiv2fuzzer.Type returns = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message InterfaceFunction {
|
message InterfaceFunction {
|
||||||
enum StateMutability {
|
enum StateMutability {
|
||||||
PURE = 0;
|
PURE = 0;
|
||||||
VIEW = 1;
|
VIEW = 1;
|
||||||
PAYABLE = 2;
|
PAYABLE = 2;
|
||||||
}
|
}
|
||||||
required FunctionParamsAndReturns paramandret = 1;
|
required StateMutability mut = 1;
|
||||||
required StateMutability mut = 2;
|
|
||||||
required bool override = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message LibraryFunction {
|
message LibraryFunction {
|
||||||
@ -47,11 +38,8 @@ message LibraryFunction {
|
|||||||
INTERNAL = 2;
|
INTERNAL = 2;
|
||||||
PRIVATE = 3;
|
PRIVATE = 3;
|
||||||
}
|
}
|
||||||
required FunctionParamsAndReturns paramandret = 1;
|
required Visibility vis = 1;
|
||||||
required Visibility vis = 2;
|
required StateMutability mut = 2;
|
||||||
required StateMutability mut = 3;
|
|
||||||
required Block b = 4;
|
|
||||||
optional Modifier m = 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message ContractFunction {
|
message ContractFunction {
|
||||||
@ -66,144 +54,25 @@ message ContractFunction {
|
|||||||
INTERNAL = 2;
|
INTERNAL = 2;
|
||||||
PRIVATE = 3;
|
PRIVATE = 3;
|
||||||
}
|
}
|
||||||
required FunctionParamsAndReturns paramandret = 1;
|
required Visibility vis = 1;
|
||||||
required Visibility vis = 2;
|
required StateMutability mut = 2;
|
||||||
required StateMutability mut = 3;
|
required bool virtualfunc = 3;
|
||||||
required Block b = 4;
|
|
||||||
optional Modifier m = 5;
|
|
||||||
required bool implemented = 6;
|
|
||||||
required bool virtualfunc = 7;
|
|
||||||
required bool override = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Modifier {
|
|
||||||
repeated solidity.test.abiv2fuzzer.Type params = 1;
|
|
||||||
required Block b = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Expressions
|
|
||||||
message Expression {
|
|
||||||
oneof expr_oneof {
|
|
||||||
Literal lit = 1;
|
|
||||||
BinaryOp bop = 2;
|
|
||||||
UnaryOp uop = 3;
|
|
||||||
VarRef ref = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message VarRef {
|
|
||||||
required int32 varnum = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Literal {
|
|
||||||
oneof literal_oneof {
|
|
||||||
bool blit = 1;
|
|
||||||
string slit = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message BinaryOp {
|
|
||||||
enum Operation {
|
|
||||||
ADD = 1;
|
|
||||||
SUB = 2;
|
|
||||||
MUL = 3;
|
|
||||||
DIV = 4;
|
|
||||||
}
|
|
||||||
required Operation op = 1;
|
|
||||||
required Expression arg1 = 2;
|
|
||||||
required Expression arg2 = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message UnaryOp {
|
|
||||||
enum Operation {
|
|
||||||
INC = 1;
|
|
||||||
DEC = 2;
|
|
||||||
}
|
|
||||||
required Operation op = 1;
|
|
||||||
required Expression arg = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Statements
|
|
||||||
message ElseStmt {
|
|
||||||
required Block statements = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message IfStmt {
|
|
||||||
required Expression condition = 1;
|
|
||||||
required Block statements = 2;
|
|
||||||
optional ElseStmt else = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ForStmt {
|
|
||||||
required Block pre = 1;
|
|
||||||
required Expression condition = 2;
|
|
||||||
required Block post = 3;
|
|
||||||
required Block body = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
message CaseStmt {
|
|
||||||
required Literal lit = 1;
|
|
||||||
required Block block = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SwitchStmt {
|
|
||||||
required Expression condition = 1;
|
|
||||||
repeated CaseStmt cases = 2;
|
|
||||||
optional Block default = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message BreakStmt {}
|
|
||||||
|
|
||||||
message ContinueStmt {}
|
|
||||||
|
|
||||||
message ReturnStmt {
|
|
||||||
required Expression value = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message DoStmt {
|
|
||||||
required Expression condition = 1;
|
|
||||||
required Block statements = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message WhileStmt {
|
|
||||||
required Expression condition = 1;
|
|
||||||
required Block statements = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Statement {
|
|
||||||
oneof stmt_oneof {
|
|
||||||
solidity.test.abiv2fuzzer.VarDecl var = 1;
|
|
||||||
IfStmt ifstmt = 2;
|
|
||||||
ForStmt forstmt = 3;
|
|
||||||
SwitchStmt switchstmt = 4;
|
|
||||||
BreakStmt breakstmt = 5;
|
|
||||||
ContinueStmt continuestmt = 6;
|
|
||||||
ReturnStmt returnstmt = 7;
|
|
||||||
DoStmt dostmt = 8;
|
|
||||||
WhileStmt whilestmt = 9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message Block {
|
|
||||||
repeated Statement statements = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message Library {
|
message Library {
|
||||||
repeated solidity.test.abiv2fuzzer.VarDecl state_vars = 1;
|
repeated LibraryFunction funcdef = 1;
|
||||||
repeated LibraryFunction funcdef = 2;
|
required uint64 random = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Interface {
|
message Interface {
|
||||||
repeated solidity.test.abiv2fuzzer.VarDecl state_vars = 1;
|
repeated InterfaceFunction funcdef = 1;
|
||||||
repeated InterfaceFunction funcdef = 2;
|
repeated Interface bases = 2;
|
||||||
repeated Interface ancestors = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message Contract {
|
message Contract {
|
||||||
repeated solidity.test.abiv2fuzzer.VarDecl state_vars = 1;
|
repeated ContractFunction funcdef = 1;
|
||||||
repeated ContractFunction funcdef = 2;
|
required bool abstract = 2;
|
||||||
required bool abstract = 3;
|
repeated ContractOrInterface bases = 3;
|
||||||
repeated ContractOrInterface ancestors = 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message ContractOrInterface {
|
message ContractOrInterface {
|
||||||
@ -221,8 +90,19 @@ message ContractType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Program {
|
message TestContract {
|
||||||
repeated ContractType contracts = 1;
|
enum Type {
|
||||||
|
LIBRARY = 0;
|
||||||
|
CONTRACT = 1;
|
||||||
|
}
|
||||||
|
required Type type = 1;
|
||||||
|
required uint64 programidx = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
package solidity.test.solprotofuzzer;
|
message Program {
|
||||||
|
repeated ContractType contracts = 1;
|
||||||
|
required TestContract test = 2;
|
||||||
|
required uint64 seed = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
package solidity.test.solprotofuzzer;
|
@ -17,16 +17,178 @@
|
|||||||
|
|
||||||
#include <test/tools/ossfuzz/protoToSol.h>
|
#include <test/tools/ossfuzz/protoToSol.h>
|
||||||
#include <test/tools/ossfuzz/solProto.pb.h>
|
#include <test/tools/ossfuzz/solProto.pb.h>
|
||||||
|
#include <test/tools/ossfuzz/abiV2FuzzerCommon.h>
|
||||||
|
#include <test/EVMHost.h>
|
||||||
|
|
||||||
#include <test/tools/fuzzer_common.h>
|
#include <evmone/evmone.h>
|
||||||
|
|
||||||
#include <src/libfuzzer/libfuzzer_macro.h>
|
#include <src/libfuzzer/libfuzzer_macro.h>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
static evmc::VM evmone = evmc::VM{evmc_create_evmone()};
|
||||||
|
|
||||||
|
using namespace solidity;
|
||||||
|
using namespace solidity::test;
|
||||||
using namespace solidity::test::solprotofuzzer;
|
using namespace solidity::test::solprotofuzzer;
|
||||||
|
using namespace solidity::util;
|
||||||
|
using namespace solidity::test::abiv2fuzzer;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
/// Compares two runs of EVMC returing true if they are
|
||||||
|
/// equal and false otherwise.
|
||||||
|
bool isOutputExpected(evmc::result const& _run1, evmc::result const& _run2)
|
||||||
|
{
|
||||||
|
if (_run1.output_size != _run2.output_size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (getenv("SOL_DEBUG_FILE") != nullptr)
|
||||||
|
{
|
||||||
|
unsigned r = _run1.output_data[31] | _run1.output_data[30] << 8 |
|
||||||
|
_run1.output_data[29] << 16 | _run1.output_data[28] << 24;
|
||||||
|
std::cout << r << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 [minimalBytecode, ids] = compileContract(
|
||||||
|
_sourceCode,
|
||||||
|
_contractName,
|
||||||
|
_libraryAddressMap,
|
||||||
|
_optimization
|
||||||
|
);
|
||||||
|
|
||||||
|
return deployAndExecute(
|
||||||
|
hostContext,
|
||||||
|
minimalBytecode,
|
||||||
|
ids[_methodName].asString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_PROTO_FUZZER(Program const& _input)
|
DEFINE_PROTO_FUZZER(Program const& _input)
|
||||||
{
|
{
|
||||||
ProtoConverter converter;
|
ProtoConverter converter;
|
||||||
@ -39,6 +201,47 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
|||||||
ofstream of(dump_path);
|
ofstream of(dump_path);
|
||||||
of.write(sol_source.data(), sol_source.size());
|
of.write(sol_source.data(), sol_source.size());
|
||||||
}
|
}
|
||||||
FuzzerUtil::testCompiler(sol_source, /*optimize=*/false);
|
|
||||||
|
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(),
|
||||||
|
converter.libraryTest() ? converter.libraryName() : ""
|
||||||
|
);
|
||||||
|
|
||||||
|
auto optResult = compileDeployAndExecute(
|
||||||
|
sol_source,
|
||||||
|
":C",
|
||||||
|
"test()",
|
||||||
|
frontend::OptimiserSettings::standard(),
|
||||||
|
converter.libraryTest() ? converter.libraryName() : ""
|
||||||
|
);
|
||||||
|
|
||||||
|
// Both executions should either return success or identical evmone status code
|
||||||
|
bool successState = minimalResult.status_code == EVMC_SUCCESS && optResult.status_code == EVMC_SUCCESS;
|
||||||
|
bool identicalState = minimalResult.status_code == optResult.status_code;
|
||||||
|
bool executeState = successState || identicalState;
|
||||||
|
solAssert(executeState, "Proto solc fuzzer: Different execution status");
|
||||||
|
|
||||||
|
if (successState)
|
||||||
|
solAssert(
|
||||||
|
isOutputExpected(minimalResult, optResult),
|
||||||
|
"Proto solc fuzzer: Output mismatch"
|
||||||
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user