mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Randomize calldataload and storage slots and use dictionary tokens as function argument
This commit is contained in:
parent
d066ba71a4
commit
fce65ec811
@ -1078,17 +1078,67 @@ void ProtoConverter::registerFunction(FunctionDef const* _x)
|
|||||||
m_functionDefMap.emplace(make_pair(_x, funcName));
|
m_functionDefMap.emplace(make_pair(_x, funcName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtoConverter::fillFunctionCallInput(unsigned _numInParams)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < _numInParams; i++)
|
||||||
|
{
|
||||||
|
// Throw a 4-sided dice to choose whether to populate function input
|
||||||
|
// argument from a pseudo-randomly chosen slot in one of the following
|
||||||
|
// locations: calldata, memory, storage, or yul optimizer dictionary.
|
||||||
|
unsigned diceValue = counter() % 4;
|
||||||
|
// Pseudo-randomly choose one of the first ten 32-byte
|
||||||
|
// aligned slots.
|
||||||
|
string slot = to_string((counter() % 10) * 32);
|
||||||
|
switch (diceValue)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
m_output << "calldataload(" << slot << ")";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
m_output << "mload(" << slot << ")";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
m_output << "sload(" << slot << ")";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// Call to dictionaryToken() automatically picks a token
|
||||||
|
// at a pseudo-random location.
|
||||||
|
m_output << dictionaryToken();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i < _numInParams - 1)
|
||||||
|
m_output << ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtoConverter::saveFunctionCallOutput(vector<string> const& _varsVec)
|
||||||
|
{
|
||||||
|
for (auto const& var: _varsVec)
|
||||||
|
{
|
||||||
|
// Flip a dice to choose whether to save output values
|
||||||
|
// in storage or memory.
|
||||||
|
bool coinFlip = counter() % 2 == 0;
|
||||||
|
// Pseudo-randomly choose one of the first ten 32-byte
|
||||||
|
// aligned slots.
|
||||||
|
string slot = to_string((counter() % 10) * 32);
|
||||||
|
if (coinFlip)
|
||||||
|
m_output << "sstore(" << slot << ", " << var << ")\n";
|
||||||
|
else
|
||||||
|
m_output << "mstore(" << slot << ", " << var << ")\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ProtoConverter::createFunctionCall(
|
void ProtoConverter::createFunctionCall(
|
||||||
string _funcName,
|
string _funcName,
|
||||||
unsigned _numInParams,
|
unsigned _numInParams,
|
||||||
unsigned _numOutParams
|
unsigned _numOutParams
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Prints the following to output stream "let x_i,...,x_n := "
|
|
||||||
unsigned startIdx = counter();
|
|
||||||
vector<string> varsVec{};
|
vector<string> varsVec{};
|
||||||
if (_numOutParams > 0)
|
if (_numOutParams > 0)
|
||||||
{
|
{
|
||||||
|
unsigned startIdx = counter();
|
||||||
|
// Prints the following to output stream "let x_i,...,x_n := "
|
||||||
varsVec = createVarDecls(
|
varsVec = createVarDecls(
|
||||||
startIdx,
|
startIdx,
|
||||||
startIdx + _numOutParams,
|
startIdx + _numOutParams,
|
||||||
@ -1096,24 +1146,22 @@ void ProtoConverter::createFunctionCall(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the function with the correct number of input parameters via calls to calldataload with
|
// Call the function with the correct number of input parameters
|
||||||
// incremental addresses.
|
|
||||||
m_output << _funcName << "(";
|
m_output << _funcName << "(";
|
||||||
for (unsigned i = 0; i < _numInParams; i++)
|
if (_numInParams > 0)
|
||||||
{
|
fillFunctionCallInput(_numInParams);
|
||||||
m_output << "calldataload(" << std::to_string(i*32) << ")";
|
|
||||||
if (i < _numInParams - 1)
|
|
||||||
m_output << ",";
|
|
||||||
}
|
|
||||||
m_output << ")\n";
|
m_output << ")\n";
|
||||||
|
|
||||||
// Save output values to storage
|
|
||||||
for (unsigned i = 0; i < varsVec.size(); i++)
|
|
||||||
m_output << "sstore(" << std::to_string(i*32) << ", " << varsVec[i] << ")\n";
|
|
||||||
|
|
||||||
// Add newly minted vars to current scope
|
|
||||||
if (!varsVec.empty())
|
if (!varsVec.empty())
|
||||||
|
{
|
||||||
|
// Save values returned by function so that they are reflected
|
||||||
|
// in the interpreter trace.
|
||||||
|
saveFunctionCallOutput(varsVec);
|
||||||
|
// Add newly minted vars to current scope
|
||||||
addVarsToScope(varsVec);
|
addVarsToScope(varsVec);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
yulAssert(_numOutParams == 0, "Proto fuzzer: Function return value not saved");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtoConverter::createFunctionDefAndCall(
|
void ProtoConverter::createFunctionDefAndCall(
|
||||||
|
@ -208,6 +208,21 @@ private:
|
|||||||
/// @param _numOutParams Number of output parameters in function signature
|
/// @param _numOutParams Number of output parameters in function signature
|
||||||
void createFunctionCall(std::string _funcName, unsigned _numInParams, unsigned _numOutParams);
|
void createFunctionCall(std::string _funcName, unsigned _numInParams, unsigned _numOutParams);
|
||||||
|
|
||||||
|
/// Print the yul syntax to pass input arguments to a function that has
|
||||||
|
/// @a _numInParams number of input parameters to the output stream.
|
||||||
|
/// The input arguments are pseudo-randomly chosen from calldata, memory,
|
||||||
|
/// storage, or the yul optimizer hex dictionary.
|
||||||
|
/// @param _numInParams Number of input arguments to fill
|
||||||
|
void fillFunctionCallInput(unsigned _numInParams);
|
||||||
|
|
||||||
|
/// Print the yul syntax to save values returned by a function call
|
||||||
|
/// to the output stream. The values are either stored to memory or
|
||||||
|
/// storage based on a simulated coin flip. The saved location is
|
||||||
|
/// decided pseudo-randomly.
|
||||||
|
/// @param _varsVec A vector of strings that reference variables
|
||||||
|
/// holding the return values of a function call.
|
||||||
|
void saveFunctionCallOutput(std::vector<std::string> const& _varsVec);
|
||||||
|
|
||||||
/// Register a function declaration
|
/// Register a function declaration
|
||||||
/// @param _f Pointer to a FunctionDef object
|
/// @param _f Pointer to a FunctionDef object
|
||||||
void registerFunction(FunctionDef const* _f);
|
void registerFunction(FunctionDef const* _f);
|
||||||
|
Loading…
Reference in New Issue
Block a user