Do not remove potentially reverting returndatacopy cases.

This commit is contained in:
Daniel Kirchner 2022-05-18 14:48:27 +02:00 committed by chriseth
parent 30335c13ff
commit 9fa907aac2
6 changed files with 73 additions and 1 deletions

View File

@ -9,6 +9,7 @@ Compiler Features:
Bugfixes: Bugfixes:
* ABI Encoder: When encoding an empty string coming from storage do not add a superfluous empty slot for data. * ABI Encoder: When encoding an empty string coming from storage do not add a superfluous empty slot for data.
* Yul Optimizer: Do not remove ``returndatacopy`` in cases in which it might perform out-of-bounds reads that unconditionally revert as out-of-gas. Previously, any ``returndatacopy`` that wrote to memory that was never read from was removed without accounting for the out-of-bounds condition.
### 0.8.14 (2022-05-17) ### 0.8.14 (2022-05-17)

View File

@ -157,7 +157,25 @@ void UnusedStoreEliminator::visit(Statement const& _statement)
yulAssert(isCandidateForRemoval == (isStorageWrite || (!m_ignoreMemory && isMemoryWrite))); yulAssert(isCandidateForRemoval == (isStorageWrite || (!m_ignoreMemory && isMemoryWrite)));
if (isCandidateForRemoval) if (isCandidateForRemoval)
{ {
m_stores[YulString{}].insert({&_statement, State::Undecided}); State initialState = State::Undecided;
if (*instruction == Instruction::RETURNDATACOPY)
{
initialState = State::Used;
auto startOffset = identifierNameIfSSA(funCall->arguments.at(1));
auto length = identifierNameIfSSA(funCall->arguments.at(2));
KnowledgeBase knowledge(m_dialect, [this](YulString _var) { return util::valueOrNullptr(m_ssaValues, _var); });
if (length && startOffset)
{
FunctionCall const* lengthCall = get_if<FunctionCall>(m_ssaValues.at(*length).value);
if (
knowledge.knownToBeZero(*startOffset) &&
lengthCall &&
toEVMInstruction(m_dialect, lengthCall->functionName.name) == Instruction::RETURNDATASIZE
)
initialState = State::Undecided;
}
}
m_stores[YulString{}].insert({&_statement, initialState});
vector<Operation> operations = operationsFromFunctionCall(*funCall); vector<Operation> operations = operationsFromFunctionCall(*funCall);
yulAssert(operations.size() == 1, ""); yulAssert(operations.size() == 1, "");
m_storeOperations[&_statement] = move(operations.front()); m_storeOperations[&_statement] = move(operations.front());

View File

@ -0,0 +1,9 @@
{
returndatacopy(0,0,32)
}
// ====
// EVMVersion: >homestead
// ----
// step: unusedStoreEliminator
//
// { { returndatacopy(0, 0, 32) } }

View File

@ -0,0 +1,15 @@
{
returndatacopy(0,0,returndatasize())
}
// ====
// EVMVersion: >homestead
// ----
// step: unusedStoreEliminator
//
// {
// {
// let _1 := returndatasize()
// let _2 := 0
// let _3 := 0
// }
// }

View File

@ -0,0 +1,13 @@
{
returndatacopy(0,1,returndatasize())
}
// ====
// EVMVersion: >homestead
// ----
// step: unusedStoreEliminator
//
// {
// {
// returndatacopy(0, 1, returndatasize())
// }
// }

View File

@ -0,0 +1,16 @@
{
let s := returndatasize()
returndatacopy(0,0,s)
}
// ====
// EVMVersion: >homestead
// ----
// step: unusedStoreEliminator
//
// {
// {
// let s := returndatasize()
// let _1 := 0
// let _2 := 0
// }
// }