mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Library call guard.
This commit is contained in:
parent
fda3a31930
commit
e807c9bb63
@ -80,6 +80,11 @@ string IRNames::implicitConstructor(ContractDefinition const& _contract)
|
|||||||
return "constructor_" + _contract.name() + "_" + to_string(_contract.id());
|
return "constructor_" + _contract.name() + "_" + to_string(_contract.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string IRNames::libraryAddressImmutable()
|
||||||
|
{
|
||||||
|
return "library_deploy_address";
|
||||||
|
}
|
||||||
|
|
||||||
string IRNames::constantValueFunction(VariableDeclaration const& _constant)
|
string IRNames::constantValueFunction(VariableDeclaration const& _constant)
|
||||||
{
|
{
|
||||||
solAssert(_constant.isConstant(), "");
|
solAssert(_constant.isConstant(), "");
|
||||||
|
@ -55,6 +55,7 @@ struct IRNames
|
|||||||
static std::string runtimeObject(ContractDefinition const& _contract);
|
static std::string runtimeObject(ContractDefinition const& _contract);
|
||||||
static std::string internalDispatch(YulArity const& _arity);
|
static std::string internalDispatch(YulArity const& _arity);
|
||||||
static std::string implicitConstructor(ContractDefinition const& _contract);
|
static std::string implicitConstructor(ContractDefinition const& _contract);
|
||||||
|
static std::string libraryAddressImmutable();
|
||||||
static std::string constantValueFunction(VariableDeclaration const& _constant);
|
static std::string constantValueFunction(VariableDeclaration const& _constant);
|
||||||
static std::string localVariable(VariableDeclaration const& _declaration);
|
static std::string localVariable(VariableDeclaration const& _declaration);
|
||||||
static std::string localVariable(Expression const& _expression);
|
static std::string localVariable(Expression const& _expression);
|
||||||
|
@ -94,16 +94,20 @@ string IRGenerator::generate(
|
|||||||
code {
|
code {
|
||||||
<memoryInitCreation>
|
<memoryInitCreation>
|
||||||
<callValueCheck>
|
<callValueCheck>
|
||||||
<?notLibrary>
|
<?library>
|
||||||
|
<!library>
|
||||||
<?constructorHasParams> let <constructorParams> := <copyConstructorArguments>() </constructorHasParams>
|
<?constructorHasParams> let <constructorParams> := <copyConstructorArguments>() </constructorHasParams>
|
||||||
<implicitConstructor>(<constructorParams>)
|
<implicitConstructor>(<constructorParams>)
|
||||||
</notLibrary>
|
</library>
|
||||||
<deploy>
|
<deploy>
|
||||||
<functions>
|
<functions>
|
||||||
}
|
}
|
||||||
object "<RuntimeObject>" {
|
object "<RuntimeObject>" {
|
||||||
code {
|
code {
|
||||||
<memoryInitRuntime>
|
<memoryInitRuntime>
|
||||||
|
<?library>
|
||||||
|
let called_via_delegatecall := iszero(eq(loadimmutable("<library_address>"), address()))
|
||||||
|
</library>
|
||||||
<dispatch>
|
<dispatch>
|
||||||
<runtimeFunctions>
|
<runtimeFunctions>
|
||||||
}
|
}
|
||||||
@ -118,7 +122,7 @@ string IRGenerator::generate(
|
|||||||
m_context.registerImmutableVariable(*var);
|
m_context.registerImmutableVariable(*var);
|
||||||
|
|
||||||
t("CreationObject", IRNames::creationObject(_contract));
|
t("CreationObject", IRNames::creationObject(_contract));
|
||||||
t("notLibrary", !_contract.isLibrary());
|
t("library", _contract.isLibrary());
|
||||||
|
|
||||||
FunctionDefinition const* constructor = _contract.constructor();
|
FunctionDefinition const* constructor = _contract.constructor();
|
||||||
t("callValueCheck", !constructor || !constructor->isPayable() ? callValueCheck() : "");
|
t("callValueCheck", !constructor || !constructor->isPayable() ? callValueCheck() : "");
|
||||||
@ -156,6 +160,7 @@ string IRGenerator::generate(
|
|||||||
|
|
||||||
// Do not register immutables to avoid assignment.
|
// Do not register immutables to avoid assignment.
|
||||||
t("RuntimeObject", IRNames::runtimeObject(_contract));
|
t("RuntimeObject", IRNames::runtimeObject(_contract));
|
||||||
|
t("library_address", IRNames::libraryAddressImmutable());
|
||||||
t("dispatch", dispatchRoutine(_contract));
|
t("dispatch", dispatchRoutine(_contract));
|
||||||
generateQueuedFunctions();
|
generateQueuedFunctions();
|
||||||
generateInternalDispatchFunctions();
|
generateInternalDispatchFunctions();
|
||||||
@ -747,20 +752,30 @@ string IRGenerator::deployCode(ContractDefinition const& _contract)
|
|||||||
vector<map<string, string>> loadImmutables;
|
vector<map<string, string>> loadImmutables;
|
||||||
vector<map<string, string>> storeImmutables;
|
vector<map<string, string>> storeImmutables;
|
||||||
|
|
||||||
for (VariableDeclaration const* immutable: ContractType(_contract).immutableVariables())
|
if (_contract.isLibrary())
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(immutable->type()->isValueType(), "");
|
solAssert(ContractType(_contract).immutableVariables().empty(), "");
|
||||||
solUnimplementedAssert(immutable->type()->sizeOnStack() == 1, "");
|
|
||||||
string yulVar = m_context.newYulVariable();
|
|
||||||
loadImmutables.emplace_back(map<string, string>{
|
|
||||||
{"var"s, yulVar},
|
|
||||||
{"memoryOffset"s, to_string(m_context.immutableMemoryOffset(*immutable))}
|
|
||||||
});
|
|
||||||
storeImmutables.emplace_back(map<string, string>{
|
storeImmutables.emplace_back(map<string, string>{
|
||||||
{"var"s, yulVar},
|
{"var"s, "address()"},
|
||||||
{"immutableName"s, to_string(immutable->id())}
|
{"immutableName"s, IRNames::libraryAddressImmutable()}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
for (VariableDeclaration const* immutable: ContractType(_contract).immutableVariables())
|
||||||
|
{
|
||||||
|
solUnimplementedAssert(immutable->type()->isValueType(), "");
|
||||||
|
solUnimplementedAssert(immutable->type()->sizeOnStack() == 1, "");
|
||||||
|
string yulVar = m_context.newYulVariable();
|
||||||
|
loadImmutables.emplace_back(map<string, string>{
|
||||||
|
{"var"s, yulVar},
|
||||||
|
{"memoryOffset"s, to_string(m_context.immutableMemoryOffset(*immutable))}
|
||||||
|
});
|
||||||
|
storeImmutables.emplace_back(map<string, string>{
|
||||||
|
{"var"s, yulVar},
|
||||||
|
{"immutableName"s, to_string(immutable->id())}
|
||||||
|
});
|
||||||
|
}
|
||||||
t("loadImmutables", std::move(loadImmutables));
|
t("loadImmutables", std::move(loadImmutables));
|
||||||
// reverse order to ease stack strain
|
// reverse order to ease stack strain
|
||||||
reverse(storeImmutables.begin(), storeImmutables.end());
|
reverse(storeImmutables.begin(), storeImmutables.end());
|
||||||
@ -784,6 +799,7 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
|||||||
case <functionSelector>
|
case <functionSelector>
|
||||||
{
|
{
|
||||||
// <functionName>
|
// <functionName>
|
||||||
|
<delegatecallCheck>
|
||||||
<callValueCheck>
|
<callValueCheck>
|
||||||
<?+params>let <params> := </+params> <abiDecode>(4, calldatasize())
|
<?+params>let <params> := </+params> <abiDecode>(4, calldatasize())
|
||||||
<?+retParams>let <retParams> := </+retParams> <function>(<params>)
|
<?+retParams>let <retParams> := </+retParams> <function>(<params>)
|
||||||
@ -806,7 +822,18 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
|||||||
templ["functionSelector"] = "0x" + function.first.hex();
|
templ["functionSelector"] = "0x" + function.first.hex();
|
||||||
FunctionTypePointer const& type = function.second;
|
FunctionTypePointer const& type = function.second;
|
||||||
templ["functionName"] = type->externalSignature();
|
templ["functionName"] = type->externalSignature();
|
||||||
templ["callValueCheck"] = type->isPayable() ? "" : callValueCheck();
|
string delegatecallCheck;
|
||||||
|
if (_contract.isLibrary())
|
||||||
|
{
|
||||||
|
solAssert(!type->isPayable(), "");
|
||||||
|
if (type->stateMutability() > StateMutability::View)
|
||||||
|
// If the function is not a view function and is called without DELEGATECALL,
|
||||||
|
// we revert.
|
||||||
|
// TODO add revert message.
|
||||||
|
delegatecallCheck = "if iszero(called_via_delegatecall) { revert(0, 0) }";
|
||||||
|
}
|
||||||
|
templ["delegatecallCheck"] = delegatecallCheck;
|
||||||
|
templ["callValueCheck"] = (type->isPayable() || _contract.isLibrary()) ? "" : callValueCheck();
|
||||||
|
|
||||||
unsigned paramVars = make_shared<TupleType>(type->parameterTypes())->sizeOnStack();
|
unsigned paramVars = make_shared<TupleType>(type->parameterTypes())->sizeOnStack();
|
||||||
unsigned retVars = make_shared<TupleType>(type->returnParameterTypes())->sizeOnStack();
|
unsigned retVars = make_shared<TupleType>(type->returnParameterTypes())->sizeOnStack();
|
||||||
@ -827,8 +854,16 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
|||||||
templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), false);
|
templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), false);
|
||||||
}
|
}
|
||||||
t("cases", functions);
|
t("cases", functions);
|
||||||
|
if (FunctionDefinition const* etherReceiver = _contract.receiveFunction())
|
||||||
|
{
|
||||||
|
solAssert(!_contract.isLibrary(), "");
|
||||||
|
t("receiveEther", m_context.enqueueFunctionForCodeGeneration(*etherReceiver) + "() stop()");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
t("receiveEther", "");
|
||||||
if (FunctionDefinition const* fallback = _contract.fallbackFunction())
|
if (FunctionDefinition const* fallback = _contract.fallbackFunction())
|
||||||
{
|
{
|
||||||
|
solAssert(!_contract.isLibrary(), "");
|
||||||
string fallbackCode;
|
string fallbackCode;
|
||||||
if (!fallback->isPayable())
|
if (!fallback->isPayable())
|
||||||
fallbackCode += callValueCheck() + "\n";
|
fallbackCode += callValueCheck() + "\n";
|
||||||
@ -846,10 +881,6 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
t("fallback", "revert(0, 0)");
|
t("fallback", "revert(0, 0)");
|
||||||
if (FunctionDefinition const* etherReceiver = _contract.receiveFunction())
|
|
||||||
t("receiveEther", m_context.enqueueFunctionForCodeGeneration(*etherReceiver) + "() stop()");
|
|
||||||
else
|
|
||||||
t("receiveEther", "");
|
|
||||||
return t.render();
|
return t.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1664,7 +1664,10 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
FunctionType const& functionType = dynamic_cast<FunctionType const&>(
|
FunctionType const& functionType = dynamic_cast<FunctionType const&>(
|
||||||
*_memberAccess.expression().annotation().type
|
*_memberAccess.expression().annotation().type
|
||||||
);
|
);
|
||||||
if (functionType.kind() == FunctionType::Kind::External)
|
if (
|
||||||
|
functionType.kind() == FunctionType::Kind::External ||
|
||||||
|
functionType.kind() == FunctionType::Kind::DelegateCall
|
||||||
|
)
|
||||||
define(IRVariable{_memberAccess}, IRVariable(_memberAccess.expression()).part("functionSelector"));
|
define(IRVariable{_memberAccess}, IRVariable(_memberAccess.expression()).part("functionSelector"));
|
||||||
else if (functionType.kind() == FunctionType::Kind::Declaration)
|
else if (functionType.kind() == FunctionType::Kind::Declaration)
|
||||||
{
|
{
|
||||||
@ -1672,7 +1675,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
|
|||||||
define(IRVariable{_memberAccess}) << formatNumber(functionType.externalIdentifier() << 224) << "\n";
|
define(IRVariable{_memberAccess}) << formatNumber(functionType.externalIdentifier() << 224) << "\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
solAssert(false, "Invalid use of .selector");
|
solAssert(false, "Invalid use of .selector: " + functionType.toString(false));
|
||||||
}
|
}
|
||||||
else if (member == "address")
|
else if (member == "address")
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >=byzantium
|
// EVMVersion: >=byzantium
|
||||||
// ----
|
// ----
|
||||||
// library: L
|
// library: L
|
||||||
|
@ -23,6 +23,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// library: L
|
// library: L
|
||||||
|
@ -22,6 +22,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// library: L
|
// library: L
|
||||||
|
@ -20,6 +20,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// EVMVersion: >homestead
|
// EVMVersion: >homestead
|
||||||
// ----
|
// ----
|
||||||
// library: L
|
// library: L
|
||||||
|
Loading…
Reference in New Issue
Block a user