mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9549 from ethereum/yul-reserved
[BREAKING] Disallow using reserved identifiers in Yul
This commit is contained in:
commit
ef3bcbda97
@ -26,6 +26,7 @@ Breaking Changes:
|
|||||||
* Type System: Support ``address(...).codehash`` to retrieve the codehash of an account.
|
* Type System: Support ``address(...).codehash`` to retrieve the codehash of an account.
|
||||||
* Type System: Unary negation can only be used on signed integers, not on unsigned integers.
|
* Type System: Unary negation can only be used on signed integers, not on unsigned integers.
|
||||||
* View Pure Checker: Mark ``chainid`` as view.
|
* View Pure Checker: Mark ``chainid`` as view.
|
||||||
|
* Yul: Disallow the use of reserved identifiers, such as EVM instructions, even if they are not available in the given dialect / EVM version.
|
||||||
|
|
||||||
Language Features:
|
Language Features:
|
||||||
* Super constructors can now be called using the member notation e.g. ``M.C(123)``.
|
* Super constructors can now be called using the member notation e.g. ``M.C(123)``.
|
||||||
|
@ -570,6 +570,12 @@ void AsmAnalyzer::expectValidIdentifier(YulString _identifier, SourceLocation co
|
|||||||
"\"" + _identifier.str() + "\" is not a valid identifier (contains consecutive dots)."
|
"\"" + _identifier.str() + "\" is not a valid identifier (contains consecutive dots)."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (m_dialect.reservedIdentifier(_identifier))
|
||||||
|
m_errorReporter.declarationError(
|
||||||
|
5017_error,
|
||||||
|
_location,
|
||||||
|
"The identifier \"" + _identifier.str() + "\" is reserved and can not be used."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsmAnalyzer::expectValidType(YulString _type, SourceLocation const& _location)
|
void AsmAnalyzer::expectValidType(YulString _type, SourceLocation const& _location)
|
||||||
|
@ -68,6 +68,9 @@ struct Dialect: boost::noncopyable
|
|||||||
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
|
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
|
||||||
virtual BuiltinFunction const* builtin(YulString /*_name*/) const { return nullptr; }
|
virtual BuiltinFunction const* builtin(YulString /*_name*/) const { return nullptr; }
|
||||||
|
|
||||||
|
/// @returns true if the identifier is reserved. This includes the builtins too.
|
||||||
|
virtual bool reservedIdentifier(YulString _name) const { return builtin(_name) != nullptr; }
|
||||||
|
|
||||||
virtual BuiltinFunction const* discardFunction(YulString /* _type */) const { return nullptr; }
|
virtual BuiltinFunction const* discardFunction(YulString /* _type */) const { return nullptr; }
|
||||||
virtual BuiltinFunction const* equalityFunction(YulString /* _type */) const { return nullptr; }
|
virtual BuiltinFunction const* equalityFunction(YulString /* _type */) const { return nullptr; }
|
||||||
virtual BuiltinFunction const* booleanNegationFunction() const { return nullptr; }
|
virtual BuiltinFunction const* booleanNegationFunction() const { return nullptr; }
|
||||||
|
@ -109,6 +109,26 @@ pair<YulString, BuiltinFunctionForEVM> createFunction(
|
|||||||
return {name, f};
|
return {name, f};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set<YulString> createReservedIdentifiers()
|
||||||
|
{
|
||||||
|
set<YulString> reserved;
|
||||||
|
for (auto const& instr: evmasm::c_instructions)
|
||||||
|
{
|
||||||
|
string name = instr.first;
|
||||||
|
transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
|
||||||
|
reserved.emplace(name);
|
||||||
|
}
|
||||||
|
reserved += vector<YulString>{
|
||||||
|
"linkersymbol"_yulstring,
|
||||||
|
"datasize"_yulstring,
|
||||||
|
"dataoffset"_yulstring,
|
||||||
|
"datacopy"_yulstring,
|
||||||
|
"setimmutable"_yulstring,
|
||||||
|
"loadimmutable"_yulstring,
|
||||||
|
};
|
||||||
|
return reserved;
|
||||||
|
}
|
||||||
|
|
||||||
map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess)
|
map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess)
|
||||||
{
|
{
|
||||||
map<YulString, BuiltinFunctionForEVM> builtins;
|
map<YulString, BuiltinFunctionForEVM> builtins;
|
||||||
@ -266,7 +286,8 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
|||||||
EVMDialect::EVMDialect(langutil::EVMVersion _evmVersion, bool _objectAccess):
|
EVMDialect::EVMDialect(langutil::EVMVersion _evmVersion, bool _objectAccess):
|
||||||
m_objectAccess(_objectAccess),
|
m_objectAccess(_objectAccess),
|
||||||
m_evmVersion(_evmVersion),
|
m_evmVersion(_evmVersion),
|
||||||
m_functions(createBuiltins(_evmVersion, _objectAccess))
|
m_functions(createBuiltins(_evmVersion, _objectAccess)),
|
||||||
|
m_reserved(createReservedIdentifiers())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,6 +300,11 @@ BuiltinFunctionForEVM const* EVMDialect::builtin(YulString _name) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EVMDialect::reservedIdentifier(YulString _name) const
|
||||||
|
{
|
||||||
|
return m_reserved.count(_name) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version)
|
EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version)
|
||||||
{
|
{
|
||||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace solidity::yul
|
namespace solidity::yul
|
||||||
{
|
{
|
||||||
@ -70,6 +71,9 @@ struct EVMDialect: public Dialect
|
|||||||
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
|
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
|
||||||
BuiltinFunctionForEVM const* builtin(YulString _name) const override;
|
BuiltinFunctionForEVM const* builtin(YulString _name) const override;
|
||||||
|
|
||||||
|
/// @returns true if the identifier is reserved. This includes the builtins too.
|
||||||
|
bool reservedIdentifier(YulString _name) const override;
|
||||||
|
|
||||||
BuiltinFunctionForEVM const* discardFunction(YulString /*_type*/) const override { return builtin("pop"_yulstring); }
|
BuiltinFunctionForEVM const* discardFunction(YulString /*_type*/) const override { return builtin("pop"_yulstring); }
|
||||||
BuiltinFunctionForEVM const* equalityFunction(YulString /*_type*/) const override { return builtin("eq"_yulstring); }
|
BuiltinFunctionForEVM const* equalityFunction(YulString /*_type*/) const override { return builtin("eq"_yulstring); }
|
||||||
BuiltinFunctionForEVM const* booleanNegationFunction() const override { return builtin("iszero"_yulstring); }
|
BuiltinFunctionForEVM const* booleanNegationFunction() const override { return builtin("iszero"_yulstring); }
|
||||||
@ -91,6 +95,7 @@ protected:
|
|||||||
bool const m_objectAccess;
|
bool const m_objectAccess;
|
||||||
langutil::EVMVersion const m_evmVersion;
|
langutil::EVMVersion const m_evmVersion;
|
||||||
std::map<YulString, BuiltinFunctionForEVM> m_functions;
|
std::map<YulString, BuiltinFunctionForEVM> m_functions;
|
||||||
|
std::set<YulString> m_reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,5 +45,5 @@ void yul::removeEmptyBlocks(Block& _block)
|
|||||||
|
|
||||||
bool yul::isRestrictedIdentifier(Dialect const& _dialect, YulString const& _identifier)
|
bool yul::isRestrictedIdentifier(Dialect const& _dialect, YulString const& _identifier)
|
||||||
{
|
{
|
||||||
return _identifier.empty() || TokenTraits::isYulKeyword(_identifier.str()) || _dialect.builtin(_identifier);
|
return _identifier.empty() || TokenTraits::isYulKeyword(_identifier.str()) || _dialect.reservedIdentifier(_identifier);
|
||||||
}
|
}
|
||||||
|
@ -359,12 +359,6 @@ BOOST_AUTO_TEST_CASE(shift_constantinople_warning)
|
|||||||
CHECK_PARSE_WARNING("{ sar(10, 32) }", TypeError, "The \"sar\" instruction is only available for Constantinople-compatible VMs");
|
CHECK_PARSE_WARNING("{ sar(10, 32) }", TypeError, "The \"sar\" instruction is only available for Constantinople-compatible VMs");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(jump_error)
|
|
||||||
{
|
|
||||||
CHECK_PARSE_WARNING("{ jump(44) }", DeclarationError, "Function not found.");
|
|
||||||
CHECK_PARSE_WARNING("{ jumpi(44, 2) }", DeclarationError, "Function not found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END() // }}}
|
BOOST_AUTO_TEST_SUITE_END() // }}}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -8,3 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
|
// DeclarationError 5017: (63-90): The identifier "linkersymbol" is reserved and can not be used.
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
assembly {
|
||||||
|
let linkersymbol := 1
|
||||||
|
let datacopy := 1
|
||||||
|
let swap16 := 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// DeclarationError 5017: (67-79): The identifier "linkersymbol" is reserved and can not be used.
|
||||||
|
// DeclarationError 5017: (95-103): The identifier "datacopy" is reserved and can not be used.
|
||||||
|
// DeclarationError 5017: (119-125): The identifier "swap16" is reserved and can not be used.
|
@ -0,0 +1,16 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
assembly {
|
||||||
|
let shl := 1
|
||||||
|
}
|
||||||
|
assembly {
|
||||||
|
pop(shl(1, 2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: =byzantium
|
||||||
|
// ----
|
||||||
|
// DeclarationError 5017: (67-70): The identifier "shl" is reserved and can not be used.
|
||||||
|
// TypeError 6612: (107-110): The "shl" instruction is only available for Constantinople-compatible VMs (you are currently compiling for "byzantium").
|
||||||
|
// TypeError 3950: (107-116): Expected expression to evaluate to one value, but got 0 values instead.
|
@ -0,0 +1,14 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
assembly {
|
||||||
|
let shl := 1
|
||||||
|
}
|
||||||
|
assembly {
|
||||||
|
pop(shl(1, 2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >=constantinople
|
||||||
|
// ----
|
||||||
|
// ParserError 5568: (67-70): Cannot use builtin function name "shl" as identifier name.
|
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
function g_(x) -> z_ {
|
||||||
|
if calldataload(1) { z_ := g_(x) }
|
||||||
|
sstore(z_, calldataload(add(x, 1)))
|
||||||
|
}
|
||||||
|
function datasize_(x) -> linkersymbol_ {
|
||||||
|
if calldataload(0) { linkersymbol_ := datasize_(x) }
|
||||||
|
sstore(linkersymbol_, calldataload(linkersymbol_))
|
||||||
|
}
|
||||||
|
let dataoffset_ := datasize_(7)
|
||||||
|
let x_ := g_(9)
|
||||||
|
sstore(dataoffset_, x_)
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// step: fullSuite
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// {
|
||||||
|
// let dataoffset_ := datasize_(7)
|
||||||
|
// sstore(dataoffset_, g(9))
|
||||||
|
// }
|
||||||
|
// function g(x) -> z
|
||||||
|
// {
|
||||||
|
// if calldataload(1) { z := g(x) }
|
||||||
|
// sstore(z, calldataload(add(x, 1)))
|
||||||
|
// }
|
||||||
|
// function datasize_(x) -> linkersymbol_
|
||||||
|
// {
|
||||||
|
// if calldataload(linkersymbol_) { linkersymbol_ := datasize_(x) }
|
||||||
|
// sstore(linkersymbol_, calldataload(linkersymbol_))
|
||||||
|
// }
|
||||||
|
// }
|
@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
let addr:u256 := linkersymbol("contract/library.sol:L")
|
let addr:u256 := linkersymbol("contract/library.sol:L")
|
||||||
|
function linkersymbol(x) {}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
// dialect: evmTyped
|
// dialect: evmTyped
|
||||||
// ----
|
// ----
|
||||||
|
// ParserError 5568: (75-87): Cannot use builtin function name "linkersymbol" as identifier name.
|
||||||
|
@ -6,3 +6,4 @@
|
|||||||
let s := ""
|
let s := ""
|
||||||
datacopy(x, "11", s)
|
datacopy(x, "11", s)
|
||||||
}
|
}
|
||||||
|
// ----
|
||||||
|
Loading…
Reference in New Issue
Block a user