Validate expected literal kind for yul::Dialect builtins

Co-authored-by: Daniel Kirchner <daniel@ekpyron.org>
This commit is contained in:
Alex Beregszaszi 2020-08-04 16:37:36 +01:00
parent f6a57af809
commit 3a617f9cf2
2 changed files with 38 additions and 20 deletions

View File

@ -4,7 +4,7 @@ Language Features:
Compiler Features: Compiler Features:
* Yul: Report error when using non-string literals for ``datasize()``, ``dataoffset()``, ``linkersymbol()``, ``loadimmutable()``, ``setimmutable()``.
Bugfixes: Bugfixes:
* Optimizer: Keep side-effects of ``x`` in ``byte(a, shr(b, x))`` even if the constants ``a`` and ``b`` would make the expression zero unconditionally. This optimizer rule is very hard if not impossible to trigger in a way that it can result in invalid code, though. * Optimizer: Keep side-effects of ``x`` in ``byte(a, shr(b, x))`` even if the constants ``a`` and ``b`` would make the expression zero unconditionally. This optimizer rule is very hard if not impossible to trigger in a way that it can result in invalid code, though.

View File

@ -44,6 +44,20 @@ using namespace solidity::yul;
using namespace solidity::util; using namespace solidity::util;
using namespace solidity::langutil; using namespace solidity::langutil;
namespace
{
inline string to_string(LiteralKind _kind)
{
switch (_kind)
{
case LiteralKind::Number: return "number";
case LiteralKind::Boolean: return "boolean";
case LiteralKind::String: return "string";
default: yulAssert(false, "");
}
}
}
bool AsmAnalyzer::analyze(Block const& _block) bool AsmAnalyzer::analyze(Block const& _block)
{ {
auto watcher = m_errorReporter.errorWatcher(); auto watcher = m_errorReporter.errorWatcher();
@ -318,15 +332,7 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
for (size_t i = _funCall.arguments.size(); i > 0; i--) for (size_t i = _funCall.arguments.size(); i > 0; i--)
{ {
Expression const& arg = _funCall.arguments[i - 1]; Expression const& arg = _funCall.arguments[i - 1];
bool isLiteralArgument = literalArguments && (*literalArguments)[i - 1].has_value(); if (auto literalArgumentKind = literalArguments ? literalArguments->at(i - 1) : std::nullopt)
bool isStringLiteral = holds_alternative<Literal>(arg) && get<Literal>(arg).kind == LiteralKind::String;
if (isLiteralArgument && isStringLiteral)
argTypes.emplace_back(expectUnlimitedStringLiteral(get<Literal>(arg)));
else
argTypes.emplace_back(expectExpression(arg));
if (isLiteralArgument)
{ {
if (!holds_alternative<Literal>(arg)) if (!holds_alternative<Literal>(arg))
m_errorReporter.typeError( m_errorReporter.typeError(
@ -334,18 +340,30 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
_funCall.functionName.location, _funCall.functionName.location,
"Function expects direct literals as arguments." "Function expects direct literals as arguments."
); );
else if ( else if (*literalArgumentKind != get<Literal>(arg).kind)
m_errorReporter.typeError(
5859_error,
get<Literal>(arg).location,
"Function expects " + to_string(*literalArgumentKind) + " literal."
);
else if (*literalArgumentKind == LiteralKind::String)
{
if (
_funCall.functionName.name.str() == "datasize" || _funCall.functionName.name.str() == "datasize" ||
_funCall.functionName.name.str() == "dataoffset" _funCall.functionName.name.str() == "dataoffset"
) )
if (!m_dataNames.count(std::get<Literal>(arg).value)) if (!m_dataNames.count(get<Literal>(arg).value))
m_errorReporter.typeError( m_errorReporter.typeError(
3517_error, 3517_error,
_funCall.functionName.location, get<Literal>(arg).location,
"Unknown data object \"" + std::get<Literal>(arg).value.str() + "\"." "Unknown data object \"" + std::get<Literal>(arg).value.str() + "\"."
); );
argTypes.emplace_back(expectUnlimitedStringLiteral(get<Literal>(arg)));
continue;
} }
} }
argTypes.emplace_back(expectExpression(arg));
}
std::reverse(argTypes.begin(), argTypes.end()); std::reverse(argTypes.begin(), argTypes.end());
if (parameterTypes && parameterTypes->size() == argTypes.size()) if (parameterTypes && parameterTypes->size() == argTypes.size())