Fix accessing memory reference types in yul codegen and clean up on memory reads.

This commit is contained in:
Daniel Kirchner 2020-05-04 14:21:48 +02:00
parent 4c1e821e01
commit c25a3eba14
4 changed files with 32 additions and 17 deletions

View File

@ -2245,7 +2245,6 @@ string YulUtilFunctions::readFromMemoryOrCalldata(Type const& _type, bool _fromC
} }
solAssert(_type.isValueType(), ""); solAssert(_type.isValueType(), "");
if (auto const* funType = dynamic_cast<FunctionType const*>(&_type)) if (auto const* funType = dynamic_cast<FunctionType const*>(&_type))
if (funType->kind() == FunctionType::Kind::External) if (funType->kind() == FunctionType::Kind::External)
return Whiskers(R"( return Whiskers(R"(
@ -2259,18 +2258,23 @@ string YulUtilFunctions::readFromMemoryOrCalldata(Type const& _type, bool _fromC
("splitFunction", splitExternalFunctionIdFunction()) ("splitFunction", splitExternalFunctionIdFunction())
.render(); .render();
return Whiskers(R"( return Whiskers(R"(
function <functionName>(memPtr) -> value { function <functionName>(ptr) -> value {
value := <load>(memPtr) <?fromCalldata>
<?needsValidation> value := calldataload(ptr)
<validate>(value) <validate>(value)
</needsValidation> <!fromCalldata>
value := <cleanup>(mload(ptr))
</fromCalldata>
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("load", _fromCalldata ? "calldataload" : "mload") ("fromCalldata", _fromCalldata)
("needsValidation", _fromCalldata) ("validate", validatorFunction(_type))
("validate", _fromCalldata ? validatorFunction(_type) : "") // Byte array elements generally need cleanup.
// Other types are cleaned as well to account for dirty memory e.g. due to inline assembly.
("cleanup", cleanupFunction(_type))
.render(); .render();
}); });
} }

View File

@ -204,7 +204,7 @@ public:
std::string readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes); std::string readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes);
std::string readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes); std::string readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes);
/// @returns a function that reads a value type from memory. /// @returns a function that reads a value type from memory. Performs cleanup.
/// signature: (addr) -> value /// signature: (addr) -> value
std::string readFromMemory(Type const& _type); std::string readFromMemory(Type const& _type);
/// @returns a function that reads a value type from calldata. /// @returns a function that reads a value type from calldata.

View File

@ -117,10 +117,12 @@ struct CopyTranslate: public yul::ASTCopier
reference.isOffset == false && reference.isSlot == false, reference.isOffset == false && reference.isSlot == false,
"Should not be called for offset/slot" "Should not be called for offset/slot"
); );
auto const& var = m_context.localVariable(*varDecl);
solAssert(var.type().sizeOnStack() == 1, "");
return yul::Identifier{ return yul::Identifier{
_identifier.location, _identifier.location,
yul::YulString{m_context.localVariable(*varDecl).name()} yul::YulString{var.commaSeparatedList()}
}; };
} }
@ -2060,13 +2062,7 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue)
")\n"; ")\n";
}, },
[&](IRLValue::Memory const& _memory) { [&](IRLValue::Memory const& _memory) {
if (_memory.byteArrayElement) if (_lvalue.type.isValueType())
define(result) <<
m_utils.cleanupFunction(_lvalue.type) <<
"(mload(" <<
_memory.address <<
"))\n";
else if (_lvalue.type.isValueType())
define(result) << define(result) <<
m_utils.readFromMemory(_lvalue.type) << m_utils.readFromMemory(_lvalue.type) <<
"(" << "(" <<

View File

@ -0,0 +1,15 @@
contract C {
function f() public pure returns (uint8 x, bool a, bool b) {
uint8[1] memory m;
assembly {
mstore(m, 257)
}
x = m[0];
a = (m[0] == 0x01);
b = (m[0] == 0x0101);
}
}
// ====
// compileViaYul: also
// ----
// f() -> 1, true, false